bitsofchris_openaugi-obsidi.../docs/CODEBASE_MAP.md
Chris Lettieri 521399efd3 M3b: Augi task-file commands; deprecate Task Dispatch
Add TaskFileService, which writes `status: pending` task files to
OpenAugi/Tasks/ via the Obsidian vault API — no shell-out, no HTTP, no
Node modules, so it works on mobile too. The file format mirrors the
parent repo's templates/task-template.md contract consumed by
task_watcher.py.

New commands (all platforms):
- Augi: Run review pass       -> "run the review pass"
- Augi: Process dashboard     -> "process the dashboard"
- Augi: Distill selection     -> selection/active-note body becomes the
                                 ## Context; distill-lens instruction

Deprecate the legacy Task Dispatch feature (it launches tmux itself,
bypassing the watcher). Kept functional for community users without the
Python watcher; steer new use to task files via docs banner, settings UI
label, and a @deprecated marker. To be removed over a release or two.

Docs: new docs/AGENT_TASKS.md; README + CODEBASE_MAP updated to lead with
the task-file flow. Tests: 18 new, including a watcher-frontmatter-regex
compat check and same-second collision handling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 08:26:30 -04:00

17 KiB

OpenAugi Codebase Map

A comprehensive reference for navigating and extending this Obsidian plugin.

Quick Reference

What Where
Plugin entry point main.ts
Settings types & defaults types/settings.ts
OpenAI API integration services/openai-service.ts
File I/O operations services/file-service.ts
Link traversal & aggregation services/distill-service.ts
Unified context discovery services/context-gathering-service.ts
Settings UI ui/settings-tab.ts
Agent task-file writer services/task-file-service.ts
Task dispatch service (deprecated) services/task-dispatch-service.ts
Task dispatch types types/task-dispatch.ts
Context modals ui/context-gathering-modal.ts, ui/context-selection-modal.ts, ui/context-preview-modal.ts
Session list modal ui/session-list-modal.ts

Project Structure

src/
├── main.ts                              # Plugin entry, command registration, service init
├── types/
│   ├── plugin.ts                        # Plugin interface
│   ├── settings.ts                      # Settings interfaces & defaults
│   ├── context.ts                       # Context gathering types
│   └── transcript.ts                    # API response types
├── services/
│   ├── openai-service.ts                # OpenAI API calls
│   ├── file-service.ts                  # File creation & output
│   ├── distill-service.ts               # Content aggregation, link traversal
│   ├── context-gathering-service.ts     # Unified discovery orchestration
│   ├── task-file-service.ts             # Pending task files → OpenAugi/Tasks/ (watcher trigger)
│   └── task-dispatch-service.ts         # tmux session & agent dispatch (deprecated)
├── types/
│   ├── plugin.ts                        # Plugin interface
│   ├── settings.ts                      # Settings interfaces & defaults
│   ├── context.ts                       # Context gathering types
│   ├── transcript.ts                    # API response types
│   └── task-dispatch.ts                 # Task dispatch types (agents, sessions, frontmatter)
├── ui/
│   ├── settings-tab.ts                  # Settings panel
│   ├── loading-indicator.ts             # Status bar spinner
│   ├── context-gathering-modal.ts       # Stage 1: Discovery config
│   ├── context-selection-modal.ts       # Stage 2: Checkbox selection
│   ├── context-preview-modal.ts         # Stage 3: Preview & action
│   ├── prompt-selection-modal.ts        # Custom prompt picker
│   ├── session-list-modal.ts            # Task dispatch session list
│   └── recent-activity-modal.ts         # (Legacy)
└── utils/
    └── filename-utils.ts                # Sanitization, backlink mapping

Services Architecture

OpenAIService (openai-service.ts)

Handles all AI interactions.

Key Methods:

  • parseTranscript(content) - Voice transcript → atomic notes + tasks + summary
  • distillContent(content, customPrompt?) - Multiple notes → atomic notes + summary
  • publishContent(content, customPrompt?) - Notes → single polished blog post

API Details:

  • Endpoint: https://api.openai.com/v1/chat/completions
  • Model: Configurable (GPT-5, GPT-5 Mini, GPT-5 Nano, or custom)
  • Uses JSON Schema for structured outputs (distill/transcript)
  • Free-form text for publishing

Prompt Customization:

  • Extracts context: sections from notes to customize processing
  • Supports custom prompt files from OpenAugi/Prompts/

FileService (file-service.ts)

Manages all file output.

Key Methods:

  • writeTranscriptFiles(filename, data) - Creates summary + atomic notes from transcript
  • writeDistilledFiles(rootFile, data) - Creates distilled summary + atomic notes
  • writePublishedPost(content, sourceNotes, promptName) - Creates published post with frontmatter

Output Organization:

OpenAugi/
├── Summaries/           # Summary files
│   ├── [name] - summary.md
│   └── [name] - distilled.md
├── Notes/               # Atomic notes in session folders
│   ├── Transcript YYYY-MM-DD HH-mm-ss/
│   └── Distill [Name] YYYY-MM-DD HH-mm-ss/
├── Published/           # Blog posts
│   └── [Title] - Published YYYY-MM-DD.md
└── Prompts/             # Custom prompt templates

Features:

  • Automatic collision handling (appends -1, -2, etc.)
  • Backlink mapping (original titles → sanitized filenames)
  • Session-based folders for organization

DistillService (distill-service.ts)

Content discovery and aggregation.

Discovery Methods:

  • getLinkedNotes(file) - Get all forward-linked notes from a file
  • getBacklinksForFile(targetFile) - Get all notes that link TO the target file
  • getBacklinkSnippets(targetFile, sourceFile, contextLines) - Extract context around backlinks
  • getRecentlyModifiedNotes(daysBack, excludeFolders, fromDate?, toDate?) - Time-based discovery

Aggregation:

  • aggregateContent(files, timeWindowDays?) - Combine notes into single content string

Link Discovery Supports:

  • [[wikilinks]] and embeds
  • Dataview queries (if plugin available)
  • Checkbox collections: only [x] checked items
  • Backlinks - Notes that link TO discovered notes (header section/line extraction)

Journal Filtering:

  • Detects date headers (e.g., ### YYYY-MM-DD)
  • Extracts only sections within time window
  • Configurable date format

ContextGatheringService (context-gathering-service.ts)

Orchestrates the unified discovery system.

Main Method:

gatherContext(config: ContextGatheringConfig): Promise<GatheredContext>

Discovery Modes:

  1. Linked Notes (BFS) - Breadth-first traversal up to 3 levels
  2. Recent Activity - Time-based discovery

Features:

  • Bidirectional link traversal (forward links + backlinks at each depth level)
  • Forward links: extract full note content
  • Backlinks: extract header section/lines around the link reference
  • Character limit enforcement
  • Folder exclusion filtering
  • Returns discovered notes with metadata (depth, source, size, isBacklink)

TaskFileService (task-file-service.ts)

Writes status: pending task files to OpenAugi/Tasks/ via the vault API — the trigger contract consumed by the OpenAugi task watcher (openaugi up in the parent repo). No Node.js modules, so it works on mobile. See AGENT_TASKS.md.

Key Methods:

  • createReviewPassTask() - Queue "run the review pass"
  • createProcessDashboardTask() - Queue "process the dashboard"
  • createDistillTask(context, sourceNote) - Queue a distill of the given content (selection or note body)

Contract:

  • File format defined in the parent repo's src/openaugi/templates/task-template.md
  • Frontmatter: status: pending, source_block_id: obsidian-plugin, source_note
  • Sections: # title, ## Context, ## User instruction, ## Task, ## Human Todo, ## Results
  • No repo/working_dir key — the watcher defaults the agent to the vault

TaskDispatchService (task-dispatch-service.ts) — DEPRECATED

Manages tmux-based agent sessions dispatched from task notes. Deprecated: it launches tmux itself, bypassing the task watcher. Kept functional for existing users; to be removed over a release or two. Prefer TaskFileService.

Key Methods:

  • launchOrAttach(file) - If tmux session exists, attach; otherwise assemble context, create session, start agent
  • killSession(file) - Kill tmux session for the given task note, update frontmatter
  • listActiveSessions() - List all task-* tmux sessions
  • killSessionById(taskId) - Kill session by ID (from session list modal)
  • openTerminal(sessionName) - Open terminal app attached to tmux session

Context Assembly:

  • Reads task note body (strips frontmatter)
  • Gets linked notes via DistillService.getLinkedNotes()
  • Aggregates via DistillService.aggregateContent()
  • Writes to temp file at /tmp/openaugi/task-{id}-context.md
  • Context injected into agent via --append-system-prompt-file (Claude Code)

Frontmatter:

  • Reads task_id, agent, status via metadataCache.getFileCache()
  • Updates session_active, last_session via fileManager.processFrontMatter()

Shell Execution:

  • Uses Node.js child_process.exec (available via Electron)
  • tmux commands: has-session, new-session, send-keys, kill-session, list-sessions
  • Terminal opening: osascript for iTerm2 or Terminal.app

Types Reference

Settings (types/settings.ts)

interface OpenAugiSettings {
  apiKey: string
  defaultModel: 'gpt-5' | 'gpt-5-mini' | 'gpt-5-nano'
  customModelOverride: string
  summaryFolder: string           // Default: 'OpenAugi/Summaries'
  notesFolder: string             // Default: 'OpenAugi/Notes'
  promptsFolder: string           // Default: 'OpenAugi/Prompts'
  publishedFolder: string         // Default: 'OpenAugi/Published'
  useDataviewIfAvailable: boolean
  enableDistillLogging: boolean
  recentActivityDefaults: {
    daysBack: number              // Default: 7
    excludeFolders: string[]      // Default: ['Templates', 'Archive', 'OpenAugi']
    filterJournalSections: boolean
    dateHeaderFormat: string      // Default: '### YYYY-MM-DD'
  }
  contextGatheringDefaults: {
    linkDepth: 1 | 2 | 3          // Default: 1
    maxCharacters: number         // Default: 100000
    filterRecentSectionsOnly: boolean
    includeBacklinks: boolean     // Default: true
    backlinkContextLines: number  // Default: 0 (0 = header section)
  }
}

Context Types (types/context.ts)

interface ContextGatheringConfig {
  sourceMode: 'linked-notes' | 'recent-activity'
  rootNote?: TFile
  linkDepth: 1 | 2 | 3
  maxCharacters: number
  timeWindow?: {
    mode: 'days-back' | 'date-range'
    daysBack?: number
    fromDate?: string
    toDate?: string
  }
  excludeFolders: string[]
  filterRecentSectionsOnly: boolean
  journalSectionDays?: number
  includeBacklinks?: boolean      // Enable backlink discovery
  backlinkContextLines?: number   // 0 = header section, N = lines before/after
}

interface DiscoveredNote {
  file: TFile
  depth: number                   // 0 = root, 1-3 = linked depth
  discoveredVia: string           // "root" | "linked from [[X]]" | "backlink from [[X]]" | "recent activity"
  estimatedChars: number
  included: boolean               // false if exceeded character limit
  isBacklink: boolean             // true if discovered via backlink
  backlinkSnippet?: string        // Extracted header section/lines (backlinks only)
  backlinkLine?: number           // Line number of link (backlinks only)
}

interface GatheredContext {
  notes: DiscoveredNote[]
  aggregatedContent: string
  totalCharacters: number
  totalNotes: number
  config: ContextGatheringConfig
  timestamp: string
}

Response Types (types/transcript.ts)

interface TranscriptResponse {
  summary: string
  notes: Array<{ title: string; content: string }>
  tasks: string[]
}

interface DistillResponse extends TranscriptResponse {
  sourceNotes: string[]
}

Command Registration

Commands are registered in main.ts:

Command ID Name Purpose
parse-transcript Parse transcript Process voice transcript (legacy)
distill-notes Distill linked notes Distill with prompt selection (legacy)
openaugi-process-notes Process notes Unified flow: linked notes
openaugi-process-recent Process recent activity Unified flow: recent activity
openaugi-save-context Save context Save raw aggregated content
augi-run-review-pass Augi: Run review pass Write pending task file: "run the review pass"
augi-process-dashboard Augi: Process dashboard Write pending task file: "process the dashboard"
augi-distill-selection Augi: Distill selection Write pending distill task for selection/active note
task-dispatch-launch Task dispatch: Launch or attach Deprecated — launch or attach to agent tmux session
task-dispatch-kill Task dispatch: Kill session Deprecated — kill active tmux session for task note
task-dispatch-list Task dispatch: List active sessions Deprecated — show modal of all active task sessions

Unified Three-Stage Pipeline

The new commands use a consistent flow:

┌─────────────────────────────────────┐
│  Stage 1: ContextGatheringModal     │
│  - Choose source mode               │
│  - Set depth, limits, filters       │
│  - Click "Discover Notes"           │
└──────────────┬──────────────────────┘
               ↓
┌─────────────────────────────────────┐
│  Stage 2: ContextSelectionModal     │
│  - Checkbox list of discovered notes│
│  - Toggle individual notes          │
│  - See character/token counts       │
└──────────────┬──────────────────────┘
               ↓
┌─────────────────────────────────────┐
│  Stage 3: ContextPreviewModal       │
│  - Final preview of context         │
│  - Path A: Save raw (no AI)         │
│  - Path B: Process with AI          │
│     → PromptSelectionModal          │
│     → Choose: Distill or Publish    │
└─────────────────────────────────────┘

Key Algorithms

Used by ContextGatheringService.discoverLinkedNotes():

Queue = [RootNote at depth 0]

while Queue not empty:
  note = Queue.dequeue()

  if totalChars + note.size > maxChars:
    mark note as excluded (overflow)
    continue

  mark note as included
  totalChars += note.size

  if depth < maxDepth:
    for each link in note:
      if not already discovered:
        Queue.enqueue(linkedNote at depth + 1)

Content Aggregation Format

Notes are combined with clear boundaries:

# Note: [Note Title 1]

[Full content of note 1]

# Note: [Note Title 2]

[Full content of note 2]

During file creation:

  1. Register mapping: "Original Title""sanitized-filename"
  2. When writing content, replace all [[Original Title]] with [[sanitized-filename]]
  3. Ensures backlinks work despite filename sanitization

Extending the Plugin

Adding a New Command

  1. Define command handler in main.ts
  2. Register with addCommand({ id, name, callback })
  3. Use existing services or create new ones

Adding a New Service

  1. Create file in src/services/
  2. Export class with constructor accepting App and dependencies
  3. Initialize in main.ts initializeServices()
  4. Add to plugin class properties

Adding Settings

  1. Add property to OpenAugiSettings in types/settings.ts
  2. Add default value to DEFAULT_SETTINGS
  3. Add UI control in ui/settings-tab.ts display() method

Adding a New Modal

  1. Create file in src/ui/
  2. Extend Modal from Obsidian
  3. Implement onOpen() and onClose()
  4. Use callback pattern for returning results

Build & Development

npm run dev      # Development build with watch
npm run build    # Production build
npm run typecheck # TypeScript checking

Publishing

See PUBLISHING.md for the complete release process.


Output Folders

Folder Purpose Example Files
OpenAugi/Summaries/ Summary/distilled files MyNote - distilled.md
OpenAugi/Notes/ Atomic note sessions Distill MyNote 2025-01-12 14-30-00/
OpenAugi/Published/ Blog posts My Post - Published 2025-01-12.md
OpenAugi/Prompts/ Custom prompt templates Technical Focus.md
OpenAugi/Logs/ Debug logs (if enabled) Distill context logs

Obsidian APIs Used

  • Plugin - Base plugin class
  • App - Vault and workspace access
  • TFile - File abstraction
  • Modal - Dialog windows
  • Notice - Toast notifications
  • PluginSettingTab - Settings panel
  • MetadataCache - Link resolution
  • Vault - File read/write operations

External Dependencies

  • OpenAI API - Chat completions endpoint
  • Dataview Plugin (optional) - Query execution for advanced link discovery