# Phase 4: Agent Lifecycle - Discovery

**Research Level:** 2 (Standard Research)
**Completed:** 2026-01-30

## Research Questions

1. How do we spawn Claude Code agents programmatically?
2. What's the output format for background/non-interactive agents?
3. How do we persist agent sessions across terminal close/reopen?
4. How do we manage the process lifecycle?

## Key Finding: Claude CLI with JSON Output

Use **Claude CLI** with `--output-format json` flag, not the SDK. The session_id is returned in the JSON result output:

```json
{
  "type": "result",
  "subtype": "success",
  "is_error": false,
  "duration_ms": 7899,
  "session_id": "f38b6614-d740-4441-a123-0bb3bea0d6a9",
  "result": "Claude's response...",
  "total_cost_usd": 0.08348025
}
```

### CLI Invocation Pattern

```bash
# Spawn agent with JSON output
claude -p "Fix the auth bug in src/auth.ts" --output-format json

# Resume a session (when agent was waiting for input)
claude -p "Use option A" --resume f38b6614-d740-4441-a123-0bb3bea0d6a9 --output-format json
```

### Session Persistence (AGENT-04)

**Key insight:** Session ID is primarily important when an agent stops due to waiting for a question (AskUserQuestion tool) and needs to be resumed with the user's response.

Flow:
1. Agent runs and uses AskUserQuestion → CLI exits with session_id
2. Store session_id in database, set status to `waiting_for_input`
3. User provides response via `cw agent resume <name> "response"`
4. Resume with `claude -p "response" --resume <session_id> --output-format json`

### Agent Names

Agents use human-readable names (e.g., "gastown", "chinatown") instead of UUIDs for better UX:

```bash
# Spawn with name
cw agent spawn --name gastown --task task-123 "Fix the auth bug"

# Reference by name
cw agent stop gastown
cw agent get gastown
cw agent resume gastown "Use option A"
```

### Working Directory & Worktrees

Each agent gets an isolated worktree. The CLI runs with `cwd` set to the worktree path:

```typescript
execa('claude', ['-p', prompt, '--output-format', 'json'], {
  cwd: worktree.path,  // Agent operates in isolated worktree
});
```

## Architecture Decision

### AgentManager Port Interface

Following hexagonal architecture (same as EventBus, WorktreeManager):

```typescript
interface AgentManager {
  // Spawn new agent with task assignment (AGENT-01)
  spawn(taskId: string, prompt: string): Promise<Agent>;

  // Stop running agent (AGENT-02)
  stop(agentId: string): Promise<void>;

  // List all agents with status (AGENT-03)
  list(): Promise<Agent[]>;

  // Get single agent
  get(agentId: string): Promise<Agent | null>;

  // Resume agent session (AGENT-04)
  resume(agentId: string, prompt: string): Promise<void>;
}

interface Agent {
  id: string;
  taskId: string;
  sessionId: string;      // Claude SDK session ID for persistence
  worktreeId: string;     // WorktreeManager worktree ID
  status: 'running' | 'idle' | 'stopped' | 'crashed';
  createdAt: Date;
  lastActivityAt: Date;
}
```

### Database Schema Addition

Add `agents` table to persist agent state:

```sql
CREATE TABLE agents (
  id TEXT PRIMARY KEY,
  task_id TEXT REFERENCES tasks(id),
  session_id TEXT NOT NULL,        -- Claude SDK session ID
  worktree_id TEXT NOT NULL,       -- WorktreeManager worktree ID
  status TEXT NOT NULL DEFAULT 'idle',
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL
);
```

### Integration with Existing Infrastructure

1. **WorktreeManager** - Create isolated worktree per agent
2. **EventBus** - Emit agent lifecycle events (AgentSpawned, AgentStopped, etc.)
3. **Database** - Persist agent state for session resumption
4. **tRPC** - Expose agent operations to CLI

## Requirements Mapping

| Requirement | Solution |
|-------------|----------|
| AGENT-01: Spawn with task | `AgentManager.spawn(taskId, prompt)` creates worktree, starts SDK query |
| AGENT-02: Stop agent | `AgentManager.stop(id)` - abort async generator, emit stop event |
| AGENT-03: List agents | `AgentManager.list()` - query database, return with status |
| AGENT-04: Session persistence | Store `session_id` in DB, use `resume` option to continue |
| AGENT-05: Background mode | SDK runs in Node.js event loop, no terminal needed |
| AGENT-07: JSON output | SDK streams structured messages, not raw CLI output |

## Plan Structure

**4 plans in 3 waves:**

```
Wave 1 (parallel):
  04-01: Agent schema + repository (database layer)
  04-02: AgentManager port + events (interface + types)

Wave 2:
  04-03: AgentManager adapter (SDK implementation)

Wave 3:
  04-04: tRPC integration + CLI commands
```

## Sources

- [Claude Agent SDK Overview](https://platform.claude.com/docs/en/agent-sdk/overview)
- [TypeScript SDK Reference](https://platform.claude.com/docs/en/agent-sdk/typescript)
- [Claude Agent SDK TypeScript V2 Preview](https://platform.claude.com/docs/en/agent-sdk/typescript-v2-preview)
- [Claude Code CLI Reference](https://code.claude.com/docs/en/cli-reference)

---
*Discovery completed: 2026-01-30*
