# Agent Module `src/agent/` — Agent lifecycle management, output parsing, multi-provider support, and account failover. ## File Inventory | File | Purpose | |------|---------| | `types.ts` | Core types: `AgentInfo`, `AgentManager` interface, `SpawnOptions`, `StreamEvent` | | `manager.ts` | `MultiProviderAgentManager` — main orchestrator class | | `process-manager.ts` | `AgentProcessManager` — worktree creation, command building, detached spawn | | `output-handler.ts` | `OutputHandler` — JSONL stream parsing, completion detection, proposal creation | | `file-tailer.ts` | `FileTailer` — watches output files, emits line events | | `file-io.ts` | Input/output file I/O: frontmatter writing, signal.json reading, tiptap conversion | | `markdown-to-tiptap.ts` | Markdown to Tiptap JSON conversion using MarkdownManager | | `index.ts` | Public exports, `ClaudeAgentManager` deprecated alias | ### Sub-modules | Directory | Purpose | |-----------|---------| | `providers/` | Provider registry, presets (7 providers), config types | | `providers/parsers/` | Provider-specific output parsers (Claude JSONL, generic line) | | `accounts/` | Account discovery, config dir setup, credential management, usage API | | `credentials/` | `AccountCredentialManager` — credential injection per account | | `lifecycle/` | `LifecycleController` — retry policy, signal recovery, missing signal instructions | | `prompts/` | Mode-specific prompt builders (execute, discuss, breakdown, decompose, refine) | ## Key Flows ### Spawning an Agent 1. **tRPC procedure** calls `agentManager.spawn(options)` 2. Manager generates alias (adjective-animal), creates DB record 3. `AgentProcessManager.createWorktree()` — creates git worktree at `.cw-worktrees/agent//` 4. `file-io.writeInputFiles()` — writes `.cw/input/` with initiative, pages, phase, task as frontmatter 5. Provider config builds spawn command via `buildSpawnCommand()` 6. `spawnDetached()` — launches detached child process with file output redirection 7. `FileTailer` watches output file, fires `onEvent` and `onRawContent` callbacks 8. `OutputHandler.handleStreamEvent()` processes each JSONL line 9. DB record updated with PID, output file path, session ID 10. `agent:spawned` event emitted ### Completion Detection 1. `FileTailer` detects process exit 2. `OutputHandler.handleCompletion()` triggered 3. **Primary path**: Reads `.cw/output/signal.json` from agent worktree 4. Signal contains `{ status: "done"|"questions"|"error", result?, questions?, error? }` 5. Agent DB status updated accordingly (idle, waiting_for_input, crashed) 6. For `done`: proposals created from structured output; `agent:stopped` emitted 7. For `questions`: parsed and stored as `pendingQuestions`; `agent:waiting` emitted 8. **Fallback**: If signal.json missing, lifecycle controller retries with instruction injection ### Account Failover 1. On usage-limit error, `markAccountExhausted(id, until)` called 2. `findNextAvailable(provider)` returns least-recently-used non-exhausted account 3. Agent re-spawned with new account's credentials 4. `agent:account_switched` event emitted ### Resume Flow 1. tRPC `resumeAgent` called with `answers: Record` 2. Manager looks up agent's session ID and provider config 3. `buildResumeCommand()` creates resume command with session flag 4. `formatAnswersAsPrompt(answers)` converts answers to prompt text 5. New detached process spawned, same worktree, incremented session number ## Provider Configuration Providers defined in `providers/presets.ts`: | Provider | Command | Resume | Prompt Mode | |----------|---------|--------|-------------| | claude | `claude` | `--resume ` | native (`-p`) | | claude-code | `claude` | `--resume ` | native | | codex | `codex` | none | flag (`--prompt`) | | aider | `aider` | none | flag (`--message`) | | cline | `cline` | none | flag | | continue | `continue` | none | flag | | cursor-agent | `cursor` | none | flag | Each provider config specifies: `command`, `args`, `resumeStyle`, `promptMode`, `structuredOutput`, `sessionId` extraction, `nonInteractive` options. ## Output Parsing The `OutputHandler` processes JSONL streams from Claude CLI: - `text_delta` events → accumulated as text output, emitted via `agent:output` - `init` event → session ID extracted - `result` event → final result with structured data - Signal file (`signal.json`) → authoritative completion status For providers without structured output, the generic line parser accumulates raw text. ## Log Chunks Agent output is persisted to `agent_log_chunks` table: - `onRawContent` callback fires for every output chunk - Fire-and-forget DB insert (no FK to agents — survives deletion) - Session tracking: spawn=1, resume=previousMax+1 - Read path concatenates all sessions for full output history