---
phase: 04-agent-lifecycle
plan: 02
type: execute
wave: 1
depends_on: []
files_modified: [src/agent/types.ts, src/agent/index.ts, src/events/types.ts, src/events/index.ts]
autonomous: true
---

<objective>
Define AgentManager port interface and agent lifecycle domain events.

Purpose: Establish the contract for agent operations following hexagonal architecture.
Output: AgentManager port interface and AgentSpawned/AgentStopped/AgentCrashed events.
</objective>

<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/04-agent-lifecycle/DISCOVERY.md

@src/events/types.ts
@src/events/index.ts
@src/git/types.ts
</context>

<tasks>

<task type="auto">
  <name>Task 1: Define AgentManager port interface and domain types</name>
  <files>src/agent/types.ts, src/agent/index.ts</files>
  <action>
Create new agent module with port interface following WorktreeManager pattern:

```typescript
// src/agent/types.ts

/**
 * Agent Module Types
 *
 * Port interface for agent lifecycle management.
 * AgentManager is the PORT. Implementations are ADAPTERS.
 */

export type AgentStatus = 'idle' | 'running' | 'waiting_for_input' | 'stopped' | 'crashed';

/**
 * Options for spawning a new agent
 */
export interface SpawnAgentOptions {
  /** Human-readable name for the agent (e.g., 'gastown', 'chinatown') */
  name: string;
  /** Task ID to assign to agent */
  taskId: string;
  /** Initial prompt/instruction for the agent */
  prompt: string;
  /** Optional working directory (defaults to worktree path) */
  cwd?: string;
}

/**
 * Represents a Claude agent instance
 */
export interface AgentInfo {
  /** Unique identifier for this agent */
  id: string;
  /** Human-readable name for the agent */
  name: string;
  /** Task this agent is working on */
  taskId: string;
  /** Claude CLI session ID for resumption (null until first run completes) */
  sessionId: string | null;
  /** WorktreeManager worktree ID */
  worktreeId: string;
  /** Current status (waiting_for_input = paused on AskUserQuestion) */
  status: AgentStatus;
  /** When the agent was created */
  createdAt: Date;
  /** Last activity timestamp */
  updatedAt: Date;
}

/**
 * Result from agent execution
 */
export interface AgentResult {
  /** Whether the task completed successfully */
  success: boolean;
  /** Result message or error description */
  message: string;
  /** Files modified during execution */
  filesModified?: string[];
}

/**
 * AgentManager Port Interface
 *
 * Manages Claude agent lifecycle - spawn, stop, list, resume.
 *
 * Covers requirements:
 * - AGENT-01: Spawn new agent with task assignment
 * - AGENT-02: Stop running agent
 * - AGENT-03: List all agents with status
 * - AGENT-04: Resume agent session
 * - AGENT-05: Background mode (implementation detail)
 */
export interface AgentManager {
  /**
   * Spawn a new agent to work on a task.
   *
   * Creates isolated worktree, starts Claude SDK session,
   * and begins executing the prompt.
   *
   * @param options - Spawn configuration
   * @returns Agent info with session ID for later resumption
   */
  spawn(options: SpawnAgentOptions): Promise<AgentInfo>;

  /**
   * Stop a running agent.
   *
   * Gracefully stops the agent's work. Worktree is preserved
   * for potential resumption.
   *
   * @param agentId - Agent to stop
   */
  stop(agentId: string): Promise<void>;

  /**
   * List all agents with their current status.
   *
   * @returns Array of all agents
   */
  list(): Promise<AgentInfo[]>;

  /**
   * Get a specific agent by ID.
   *
   * @param agentId - Agent ID
   * @returns Agent if found, null otherwise
   */
  get(agentId: string): Promise<AgentInfo | null>;

  /**
   * Get a specific agent by name.
   *
   * @param name - Agent name (human-readable)
   * @returns Agent if found, null otherwise
   */
  getByName(name: string): Promise<AgentInfo | null>;

  /**
   * Resume an agent that's waiting for input.
   *
   * Used when agent paused on AskUserQuestion and user provides response.
   * Uses stored session ID to continue with full context.
   * Agent must be in 'waiting_for_input' status.
   *
   * @param agentId - Agent to resume
   * @param prompt - User's response to continue the agent
   */
  resume(agentId: string, prompt: string): Promise<void>;

  /**
   * Get the result of an agent's work.
   *
   * Only available after agent completes or stops.
   *
   * @param agentId - Agent ID
   * @returns Result if available, null if agent still running
   */
  getResult(agentId: string): Promise<AgentResult | null>;
}
```

Create barrel export:
```typescript
// src/agent/index.ts
export * from './types.js';
```
  </action>
  <verify>npm run build passes with no TypeScript errors</verify>
  <done>AgentManager port interface and types exported from src/agent/</done>
</task>

<task type="auto">
  <name>Task 2: Add agent lifecycle events to events module</name>
  <files>src/events/types.ts, src/events/index.ts</files>
  <action>
Add agent lifecycle events following existing patterns (ProcessSpawned, WorktreeCreated, etc.):

```typescript
// Add to src/events/types.ts

// Agent Events
export interface AgentSpawnedEvent extends DomainEvent {
  type: 'agent:spawned';
  payload: {
    agentId: string;
    name: string;
    taskId: string;
    worktreeId: string;
  };
}

export interface AgentStoppedEvent extends DomainEvent {
  type: 'agent:stopped';
  payload: {
    agentId: string;
    name: string;
    taskId: string;
    reason: 'user_requested' | 'task_complete' | 'error' | 'waiting_for_input';
  };
}

export interface AgentCrashedEvent extends DomainEvent {
  type: 'agent:crashed';
  payload: {
    agentId: string;
    name: string;
    taskId: string;
    error: string;
  };
}

export interface AgentResumedEvent extends DomainEvent {
  type: 'agent:resumed';
  payload: {
    agentId: string;
    name: string;
    taskId: string;
    sessionId: string;
  };
}

export interface AgentWaitingEvent extends DomainEvent {
  type: 'agent:waiting';
  payload: {
    agentId: string;
    name: string;
    taskId: string;
    sessionId: string;
    question: string;  // The question being asked
  };
}
```

Update the DomainEventType union to include new event types.

Export new event types from index.ts if not already using * export.
  </action>
  <verify>npm run build passes</verify>
  <done>Agent lifecycle events defined and exported from events module</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] npm run build succeeds without errors
- [ ] AgentManager interface exported from src/agent/
- [ ] Agent lifecycle events (spawned, stopped, crashed, resumed) in events module
- [ ] All types properly exported from barrel files
</verification>

<success_criteria>
- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- Port interface ready for adapter implementation
</success_criteria>

<output>
After completion, create `.planning/phases/04-agent-lifecycle/04-02-SUMMARY.md`
</output>
