diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
index 50cb564..b28d6cc 100644
--- a/.planning/ROADMAP.md
+++ b/.planning/ROADMAP.md
@@ -161,10 +161,17 @@ Plans:
**Goal**: Agent modes for concept refinement (questioning) and phase breakdown (persisting to ROADMAP.md)
**Depends on**: Phase 10
**Research**: Unlikely (internal workflow patterns)
-**Plans**: TBD
+**Plans**: 8
Plans:
-- [ ] 11-01: TBD
+- [ ] 11-01: Agent Mode Schema Extension
+- [ ] 11-02: Initiative & Phase Repositories
+- [ ] 11-03: ClaudeAgentManager Mode Support
+- [ ] 11-04: Initiative & Phase tRPC Procedures
+- [ ] 11-05: Architect Spawn Procedures
+- [ ] 11-06: CLI Commands
+- [ ] 11-07: Unit Tests
+- [ ] 11-08: E2E Tests
#### Phase 12: Phase-Task Decomposition
**Goal**: Agents break phases into individual tasks with ability to ask questions during breakdown
@@ -204,7 +211,7 @@ Phases execute in numeric order: 1 → 1.1 → 2 → 3 → 4 → 5 → 6 → 7
| 8.1. Agent Output Schema | v1.1 | 2/2 | Complete | 2026-01-31 |
| 9. Extended Scenarios | v1.1 | 2/2 | Complete | 2026-01-31 |
| 10. Multi-Question Schema | v1.2 | 4/4 | Complete | 2026-01-31 |
-| 11. Architect Agent | v1.2 | 0/? | Not started | - |
+| 11. Architect Agent | v1.2 | 0/8 | Planned | - |
| 12. Phase-Task Decomposition | v1.2 | 0/? | Not started | - |
| 13. Real Claude E2E Tests | v1.2 | 0/? | Not started | - |
diff --git a/.planning/phases/11-architect-agent/11-01-PLAN.md b/.planning/phases/11-architect-agent/11-01-PLAN.md
new file mode 100644
index 0000000..591017c
--- /dev/null
+++ b/.planning/phases/11-architect-agent/11-01-PLAN.md
@@ -0,0 +1,187 @@
+---
+phase: 11-architect-agent
+plan: 01
+type: execute
+wave: 1
+depends_on: []
+files_modified:
+ - src/agent/schema.ts
+ - src/agent/types.ts
+ - src/db/schema.ts
+ - src/agent/mock-manager.ts
+autonomous: true
+---
+
+
+Add agent mode/role support to track what type of work an agent is performing.
+
+Purpose: Enable different agent behaviors (discuss, breakdown, execute) with mode-specific output schemas so the system knows how to interpret agent output.
+
+Output: Extended agent schema with mode field, mode-specific output schemas, updated types.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Prior phase context
+@.planning/phases/10-multi-question-schema/10-01-SUMMARY.md
+
+# Source files to modify
+@src/agent/schema.ts
+@src/agent/types.ts
+@src/db/schema.ts
+@src/agent/mock-manager.ts
+
+
+
+
+
+ Task 1: Add AgentMode type and database column
+ src/agent/types.ts, src/db/schema.ts
+
+1. In src/agent/types.ts, add AgentMode type:
+ ```typescript
+ export type AgentMode = 'execute' | 'discuss' | 'breakdown';
+ ```
+
+2. In src/db/schema.ts, add mode column to agents table:
+ ```typescript
+ mode: text('mode', { enum: ['execute', 'discuss', 'breakdown'] })
+ .notNull()
+ .default('execute'),
+ ```
+
+3. Update SpawnAgentOptions in types.ts to include optional mode:
+ ```typescript
+ /** Agent operation mode (defaults to 'execute') */
+ mode?: AgentMode;
+ ```
+
+4. Update AgentInfo in types.ts to include mode:
+ ```typescript
+ /** Current operation mode */
+ mode: AgentMode;
+ ```
+
+ npm run build passes with no type errors
+ AgentMode type exists, database schema has mode column, types updated
+
+
+
+ Task 2: Create mode-specific output schemas
+ src/agent/schema.ts
+
+Add mode-specific output schemas following the existing discriminated union pattern:
+
+1. Keep existing agentOutputSchema as 'execute' mode schema (already handles done/questions/error)
+
+2. Add discussOutputSchema for discussion mode:
+ ```typescript
+ export const discussOutputSchema = z.discriminatedUnion('status', [
+ z.object({
+ status: z.literal('questions'),
+ questions: z.array(questionItemSchema),
+ context: z.string().optional(), // Summary of what's been discussed so far
+ }),
+ z.object({
+ status: z.literal('context_complete'),
+ decisions: z.array(z.object({
+ topic: z.string(),
+ decision: z.string(),
+ reason: z.string(),
+ })),
+ summary: z.string(),
+ }),
+ z.object({
+ status: z.literal('unrecoverable_error'),
+ error: z.string(),
+ }),
+ ]);
+ ```
+
+3. Add breakdownOutputSchema for breakdown mode:
+ ```typescript
+ export const breakdownOutputSchema = z.discriminatedUnion('status', [
+ z.object({
+ status: z.literal('questions'),
+ questions: z.array(questionItemSchema),
+ }),
+ z.object({
+ status: z.literal('breakdown_complete'),
+ phases: z.array(z.object({
+ number: z.number(),
+ name: z.string(),
+ description: z.string(),
+ dependencies: z.array(z.number()).optional(), // Phase numbers this depends on
+ })),
+ }),
+ z.object({
+ status: z.literal('unrecoverable_error'),
+ error: z.string(),
+ }),
+ ]);
+ ```
+
+4. Export all schemas and types.
+
+5. Create JSON schema versions for --json-schema flag (discussOutputJsonSchema, breakdownOutputJsonSchema).
+
+ npm run build passes, new schemas are exported
+ Three mode-specific output schemas exist with JSON schema versions
+
+
+
+ Task 3: Update MockAgentManager for mode support
+ src/agent/mock-manager.ts
+
+1. Update MockAgentScenario to support mode-specific scenarios:
+ - Add 'discuss' and 'breakdown' status types to the union
+ - For discuss mode: 'questions' or 'context_complete'
+ - For breakdown mode: 'questions' or 'breakdown_complete'
+
+2. Update spawn() to accept mode in SpawnAgentOptions (defaults to 'execute')
+
+3. Store mode in agent record
+
+4. Update toAgentInfo() to include mode field
+
+5. Ensure handleCompletion properly handles mode-specific statuses:
+ - 'context_complete' → agent:stopped with reason 'context_complete'
+ - 'breakdown_complete' → agent:stopped with reason 'breakdown_complete'
+
+Note: Keep backwards compatible with existing tests by defaulting to 'execute' mode.
+
+ npm test passes for mock-manager.test.ts
+ MockAgentManager supports all three modes with proper status handling
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds without errors
+- [ ] npm test passes (all existing tests still work)
+- [ ] AgentMode type is exported from src/agent/types.ts
+- [ ] All three output schemas are exported from src/agent/schema.ts
+- [ ] MockAgentManager handles mode parameter
+
+
+
+
+- All tasks completed
+- Agent mode tracking works end-to-end
+- Mode-specific output schemas are validated by Zod
+- Existing tests pass (backwards compatible)
+- No TypeScript errors
+
+
+
diff --git a/.planning/phases/11-architect-agent/11-02-PLAN.md b/.planning/phases/11-architect-agent/11-02-PLAN.md
new file mode 100644
index 0000000..548fc83
--- /dev/null
+++ b/.planning/phases/11-architect-agent/11-02-PLAN.md
@@ -0,0 +1,146 @@
+---
+phase: 11-architect-agent
+plan: 02
+type: execute
+wave: 1
+depends_on: []
+files_modified:
+ - src/db/repositories/initiative-repository.ts
+ - src/db/repositories/phase-repository.ts
+ - src/db/repositories/index.ts
+ - src/db/index.ts
+autonomous: true
+---
+
+
+Create Initiative and Phase repositories following the hexagonal port/adapter pattern.
+
+Purpose: Enable CRUD operations for initiatives and phases, which are required for the Architect agent to persist its breakdown work.
+
+Output: InitiativeRepository and PhaseRepository ports with Drizzle adapters.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Repository pattern reference
+@src/db/repositories/task-repository.ts
+@src/db/repositories/drizzle-task-repository.ts
+
+# Schema reference
+@src/db/schema.ts
+
+
+
+
+
+ Task 1: Create InitiativeRepository port and adapter
+ src/db/repositories/initiative-repository.ts, src/db/repositories/drizzle-initiative-repository.ts
+
+1. Create src/db/repositories/initiative-repository.ts (PORT):
+ ```typescript
+ import type { Initiative, NewInitiative } from '../schema.js';
+
+ export type CreateInitiativeData = Omit;
+ export type UpdateInitiativeData = Partial;
+
+ export interface InitiativeRepository {
+ create(data: CreateInitiativeData): Promise;
+ findById(id: string): Promise;
+ findAll(): Promise;
+ findByStatus(status: 'active' | 'completed' | 'archived'): Promise;
+ update(id: string, data: UpdateInitiativeData): Promise;
+ delete(id: string): Promise;
+ }
+ ```
+
+2. Create src/db/repositories/drizzle-initiative-repository.ts (ADAPTER):
+ - Follow DrizzleTaskRepository pattern exactly
+ - Use randomUUID() for id generation
+ - Set createdAt/updatedAt to new Date() on create
+ - Update updatedAt on update
+ - Fetch after insert to get defaults
+
+ npm run build passes
+ InitiativeRepository port and Drizzle adapter created
+
+
+
+ Task 2: Create PhaseRepository port and adapter
+ src/db/repositories/phase-repository.ts, src/db/repositories/drizzle-phase-repository.ts
+
+1. Create src/db/repositories/phase-repository.ts (PORT):
+ ```typescript
+ import type { Phase, NewPhase } from '../schema.js';
+
+ export type CreatePhaseData = Omit;
+ export type UpdatePhaseData = Partial;
+
+ export interface PhaseRepository {
+ create(data: CreatePhaseData): Promise;
+ findById(id: string): Promise;
+ findByInitiativeId(initiativeId: string): Promise;
+ findByNumber(initiativeId: string, number: number): Promise;
+ update(id: string, data: UpdatePhaseData): Promise;
+ delete(id: string): Promise;
+ getNextNumber(initiativeId: string): Promise;
+ }
+ ```
+
+2. Create src/db/repositories/drizzle-phase-repository.ts (ADAPTER):
+ - Follow DrizzleTaskRepository pattern
+ - findByInitiativeId returns phases ordered by number ASC
+ - getNextNumber returns MAX(number) + 1, or 1 if no phases exist
+ - Foreign key to initiative enforced by database
+
+ npm run build passes
+ PhaseRepository port and Drizzle adapter created
+
+
+
+ Task 3: Export repositories from index files
+ src/db/repositories/index.ts, src/db/index.ts
+
+1. In src/db/repositories/index.ts, add exports:
+ ```typescript
+ export type { InitiativeRepository, CreateInitiativeData, UpdateInitiativeData } from './initiative-repository.js';
+ export { DrizzleInitiativeRepository } from './drizzle-initiative-repository.js';
+
+ export type { PhaseRepository, CreatePhaseData, UpdatePhaseData } from './phase-repository.js';
+ export { DrizzlePhaseRepository } from './drizzle-phase-repository.js';
+ ```
+
+2. In src/db/index.ts, re-export the new repositories if not already done via index.ts.
+
+ npm run build passes, repositories are importable from src/db
+ All repositories exported and importable
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds without errors
+- [ ] npm test passes
+- [ ] InitiativeRepository and PhaseRepository are importable from src/db
+- [ ] Adapters follow existing patterns (randomUUID, timestamps, fetch after insert)
+
+
+
+
+- All tasks completed
+- Both repositories have port interfaces and Drizzle adapters
+- Pattern matches existing TaskRepository implementation
+- TypeScript types are correct
+
+
+
diff --git a/.planning/phases/11-architect-agent/11-03-PLAN.md b/.planning/phases/11-architect-agent/11-03-PLAN.md
new file mode 100644
index 0000000..618c6be
--- /dev/null
+++ b/.planning/phases/11-architect-agent/11-03-PLAN.md
@@ -0,0 +1,161 @@
+---
+phase: 11-architect-agent
+plan: 03
+type: execute
+wave: 2
+depends_on: ["11-01", "11-02"]
+files_modified:
+ - src/agent/manager.ts
+ - src/db/repositories/agent-repository.ts
+ - src/db/repositories/drizzle-agent-repository.ts
+autonomous: true
+---
+
+
+Update ClaudeAgentManager and AgentRepository to support agent modes.
+
+Purpose: Enable spawning agents in different modes (execute, discuss, breakdown) with mode-specific JSON schemas passed to Claude CLI.
+
+Output: Mode-aware agent spawning with correct output schema per mode.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Depends on Plan 01 for mode schemas
+@.planning/phases/11-architect-agent/11-01-SUMMARY.md
+
+# Source files to modify
+@src/agent/manager.ts
+@src/agent/schema.ts
+@src/db/repositories/agent-repository.ts
+@src/db/repositories/drizzle-agent-repository.ts
+
+
+
+
+
+ Task 1: Update AgentRepository for mode field
+ src/db/repositories/agent-repository.ts, src/db/repositories/drizzle-agent-repository.ts
+
+1. In agent-repository.ts, update CreateAgentData to include mode:
+ ```typescript
+ export type CreateAgentData = {
+ name: string;
+ taskId: string | null;
+ sessionId: string | null;
+ worktreeId: string;
+ status: AgentStatus;
+ mode?: AgentMode; // Defaults to 'execute' if not provided
+ };
+ ```
+
+2. Import AgentMode from '../agent/types.js'
+
+3. In drizzle-agent-repository.ts:
+ - Import AgentMode type
+ - Update create() to handle mode field (default to 'execute' if not provided)
+ - Ensure toAgentRecord() includes mode in return type
+
+ npm run build passes
+ AgentRepository handles mode field with 'execute' default
+
+
+
+ Task 2: Update ClaudeAgentManager for mode-specific schemas
+ src/agent/manager.ts
+
+1. Import all output JSON schemas:
+ ```typescript
+ import {
+ agentOutputSchema,
+ agentOutputJsonSchema,
+ discussOutputJsonSchema,
+ breakdownOutputJsonSchema,
+ discussOutputSchema,
+ breakdownOutputSchema,
+ } from './schema.js';
+ ```
+
+2. Add helper function to get JSON schema by mode:
+ ```typescript
+ private getJsonSchemaForMode(mode: AgentMode): object {
+ switch (mode) {
+ case 'discuss': return discussOutputJsonSchema;
+ case 'breakdown': return breakdownOutputJsonSchema;
+ case 'execute':
+ default: return agentOutputJsonSchema;
+ }
+ }
+ ```
+
+3. Update spawn() to:
+ - Extract mode from options (default to 'execute')
+ - Pass mode to repository.create()
+ - Use getJsonSchemaForMode(mode) when constructing CLI args
+
+4. Update handleAgentCompletion() to parse output based on agent mode:
+ - Fetch agent to get its mode
+ - Use appropriate schema (discussOutputSchema, breakdownOutputSchema, or agentOutputSchema)
+ - Handle mode-specific statuses:
+ - 'context_complete' → emit agent:stopped with reason 'context_complete'
+ - 'breakdown_complete' → emit agent:stopped with reason 'breakdown_complete'
+
+5. Update toAgentInfo() to include mode field from agent record.
+
+ npm run build passes
+ ClaudeAgentManager spawns agents with mode-specific JSON schemas
+
+
+
+ Task 3: Add mode to AgentStoppedEvent reasons
+ src/events/types.ts
+
+1. Update AgentStoppedEvent payload to support new stop reasons:
+ ```typescript
+ export interface AgentStoppedEvent extends BaseEvent {
+ type: 'agent:stopped';
+ payload: {
+ agentId: string;
+ name: string;
+ taskId: string;
+ reason: 'task_complete' | 'user_requested' | 'context_complete' | 'breakdown_complete';
+ };
+ }
+ ```
+
+Note: This expands the union type - existing code using 'task_complete' and 'user_requested' continues to work.
+
+ npm run build passes, existing tests pass
+ AgentStoppedEvent supports mode-specific completion reasons
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds without errors
+- [ ] npm test passes (all existing tests still work)
+- [ ] Agent can be spawned with mode='discuss' and receives discuss JSON schema
+- [ ] Agent can be spawned with mode='breakdown' and receives breakdown JSON schema
+- [ ] Default mode='execute' works as before (backwards compatible)
+
+
+
+
+- All tasks completed
+- Mode-specific JSON schemas passed to Claude CLI
+- Mode stored in database and returned in AgentInfo
+- Existing tests pass (backwards compatible with execute mode)
+
+
+
diff --git a/.planning/phases/11-architect-agent/11-04-PLAN.md b/.planning/phases/11-architect-agent/11-04-PLAN.md
new file mode 100644
index 0000000..634186a
--- /dev/null
+++ b/.planning/phases/11-architect-agent/11-04-PLAN.md
@@ -0,0 +1,271 @@
+---
+phase: 11-architect-agent
+plan: 04
+type: execute
+wave: 2
+depends_on: ["11-02"]
+files_modified:
+ - src/trpc/router.ts
+ - src/trpc/context.ts
+autonomous: true
+---
+
+
+Add Initiative and Phase tRPC procedures for CRUD operations.
+
+Purpose: Enable CLI and future UI to create, read, update, and delete initiatives and phases through type-safe RPC.
+
+Output: tRPC procedures for initiative and phase management.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Depends on Plan 02 for repositories
+@.planning/phases/11-architect-agent/11-02-SUMMARY.md
+
+# Source files
+@src/trpc/router.ts
+@src/trpc/context.ts
+
+
+
+
+
+ Task 1: Add repositories to tRPC context
+ src/trpc/context.ts
+
+1. Import InitiativeRepository and PhaseRepository types:
+ ```typescript
+ import type { InitiativeRepository } from '../db/repositories/initiative-repository.js';
+ import type { PhaseRepository } from '../db/repositories/phase-repository.js';
+ ```
+
+2. Add to TRPCContext interface:
+ ```typescript
+ initiativeRepository?: InitiativeRepository;
+ phaseRepository?: PhaseRepository;
+ ```
+
+3. Add to CreateContextOptions if needed for wiring.
+
+ npm run build passes
+ Context includes optional initiative and phase repositories
+
+
+
+ Task 2: Add Initiative tRPC procedures
+ src/trpc/router.ts
+
+1. Add helper function:
+ ```typescript
+ function requireInitiativeRepository(ctx: TRPCContext): InitiativeRepository {
+ if (!ctx.initiativeRepository) {
+ throw new TRPCError({
+ code: 'INTERNAL_SERVER_ERROR',
+ message: 'Initiative repository not available',
+ });
+ }
+ return ctx.initiativeRepository;
+ }
+ ```
+
+2. Add Initiative procedures to appRouter:
+ ```typescript
+ // Create initiative
+ createInitiative: publicProcedure
+ .input(z.object({
+ name: z.string().min(1),
+ description: z.string().optional(),
+ }))
+ .mutation(async ({ ctx, input }) => {
+ const repo = requireInitiativeRepository(ctx);
+ return repo.create({
+ name: input.name,
+ description: input.description ?? null,
+ status: 'active',
+ });
+ }),
+
+ // List all initiatives
+ listInitiatives: publicProcedure
+ .input(z.object({
+ status: z.enum(['active', 'completed', 'archived']).optional(),
+ }).optional())
+ .query(async ({ ctx, input }) => {
+ const repo = requireInitiativeRepository(ctx);
+ if (input?.status) {
+ return repo.findByStatus(input.status);
+ }
+ return repo.findAll();
+ }),
+
+ // Get initiative by ID
+ getInitiative: publicProcedure
+ .input(z.object({ id: z.string().min(1) }))
+ .query(async ({ ctx, input }) => {
+ const repo = requireInitiativeRepository(ctx);
+ const initiative = await repo.findById(input.id);
+ if (!initiative) {
+ throw new TRPCError({
+ code: 'NOT_FOUND',
+ message: `Initiative '${input.id}' not found`,
+ });
+ }
+ return initiative;
+ }),
+
+ // Update initiative
+ updateInitiative: publicProcedure
+ .input(z.object({
+ id: z.string().min(1),
+ name: z.string().min(1).optional(),
+ description: z.string().optional(),
+ status: z.enum(['active', 'completed', 'archived']).optional(),
+ }))
+ .mutation(async ({ ctx, input }) => {
+ const repo = requireInitiativeRepository(ctx);
+ const { id, ...data } = input;
+ return repo.update(id, data);
+ }),
+ ```
+
+ npm run build passes
+ Initiative CRUD procedures added to router
+
+
+
+ Task 3: Add Phase tRPC procedures
+ src/trpc/router.ts
+
+1. Add helper function:
+ ```typescript
+ function requirePhaseRepository(ctx: TRPCContext): PhaseRepository {
+ if (!ctx.phaseRepository) {
+ throw new TRPCError({
+ code: 'INTERNAL_SERVER_ERROR',
+ message: 'Phase repository not available',
+ });
+ }
+ return ctx.phaseRepository;
+ }
+ ```
+
+2. Add Phase procedures to appRouter:
+ ```typescript
+ // Create phase (auto-assigns next number)
+ createPhase: publicProcedure
+ .input(z.object({
+ initiativeId: z.string().min(1),
+ name: z.string().min(1),
+ description: z.string().optional(),
+ }))
+ .mutation(async ({ ctx, input }) => {
+ const repo = requirePhaseRepository(ctx);
+ const nextNumber = await repo.getNextNumber(input.initiativeId);
+ return repo.create({
+ initiativeId: input.initiativeId,
+ number: nextNumber,
+ name: input.name,
+ description: input.description ?? null,
+ status: 'pending',
+ });
+ }),
+
+ // List phases for initiative
+ listPhases: publicProcedure
+ .input(z.object({ initiativeId: z.string().min(1) }))
+ .query(async ({ ctx, input }) => {
+ const repo = requirePhaseRepository(ctx);
+ return repo.findByInitiativeId(input.initiativeId);
+ }),
+
+ // Get phase by ID
+ getPhase: publicProcedure
+ .input(z.object({ id: z.string().min(1) }))
+ .query(async ({ ctx, input }) => {
+ const repo = requirePhaseRepository(ctx);
+ const phase = await repo.findById(input.id);
+ if (!phase) {
+ throw new TRPCError({
+ code: 'NOT_FOUND',
+ message: `Phase '${input.id}' not found`,
+ });
+ }
+ return phase;
+ }),
+
+ // Update phase
+ updatePhase: publicProcedure
+ .input(z.object({
+ id: z.string().min(1),
+ name: z.string().min(1).optional(),
+ description: z.string().optional(),
+ status: z.enum(['pending', 'in_progress', 'completed']).optional(),
+ }))
+ .mutation(async ({ ctx, input }) => {
+ const repo = requirePhaseRepository(ctx);
+ const { id, ...data } = input;
+ return repo.update(id, data);
+ }),
+
+ // Create multiple phases at once (from breakdown)
+ createPhasesFromBreakdown: publicProcedure
+ .input(z.object({
+ initiativeId: z.string().min(1),
+ phases: z.array(z.object({
+ number: z.number(),
+ name: z.string().min(1),
+ description: z.string(),
+ })),
+ }))
+ .mutation(async ({ ctx, input }) => {
+ const repo = requirePhaseRepository(ctx);
+ const created: Phase[] = [];
+ for (const p of input.phases) {
+ const phase = await repo.create({
+ initiativeId: input.initiativeId,
+ number: p.number,
+ name: p.name,
+ description: p.description,
+ status: 'pending',
+ });
+ created.push(phase);
+ }
+ return created;
+ }),
+ ```
+
+ npm run build passes
+ Phase CRUD procedures added to router including bulk create
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds without errors
+- [ ] npm test passes
+- [ ] Initiative procedures: createInitiative, listInitiatives, getInitiative, updateInitiative
+- [ ] Phase procedures: createPhase, listPhases, getPhase, updatePhase, createPhasesFromBreakdown
+- [ ] All procedures follow existing patterns (error handling, optional repos)
+
+
+
+
+- All tasks completed
+- Initiative and Phase CRUD available via tRPC
+- Bulk phase creation supports Architect breakdown output
+- Type-safe input/output validation
+
+
+
diff --git a/.planning/phases/11-architect-agent/11-05-PLAN.md b/.planning/phases/11-architect-agent/11-05-PLAN.md
new file mode 100644
index 0000000..f87325a
--- /dev/null
+++ b/.planning/phases/11-architect-agent/11-05-PLAN.md
@@ -0,0 +1,205 @@
+---
+phase: 11-architect-agent
+plan: 05
+type: execute
+wave: 3
+depends_on: ["11-03", "11-04"]
+files_modified:
+ - src/trpc/router.ts
+autonomous: true
+---
+
+
+Add Architect-specific tRPC procedures for spawning agents in discuss/breakdown modes.
+
+Purpose: Enable spawning architect agents that use mode-specific prompts and output schemas, with convenience procedures for the discuss→breakdown workflow.
+
+Output: spawnArchitect procedure and mode-aware agent spawning.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Depends on prior plans
+@.planning/phases/11-architect-agent/11-03-SUMMARY.md
+@.planning/phases/11-architect-agent/11-04-SUMMARY.md
+
+# Source files
+@src/trpc/router.ts
+@src/agent/types.ts
+
+
+
+
+
+ Task 1: Update spawnAgent to support mode
+ src/trpc/router.ts
+
+1. Update spawnAgentInputSchema to include mode:
+ ```typescript
+ export const spawnAgentInputSchema = z.object({
+ name: z.string().min(1),
+ taskId: z.string().min(1),
+ prompt: z.string().min(1),
+ cwd: z.string().optional(),
+ mode: z.enum(['execute', 'discuss', 'breakdown']).optional(), // defaults to 'execute'
+ });
+ ```
+
+2. Update spawnAgent procedure to pass mode to agentManager.spawn():
+ ```typescript
+ spawnAgent: publicProcedure
+ .input(spawnAgentInputSchema)
+ .mutation(async ({ ctx, input }) => {
+ const agentManager = requireAgentManager(ctx);
+ return agentManager.spawn({
+ name: input.name,
+ taskId: input.taskId,
+ prompt: input.prompt,
+ cwd: input.cwd,
+ mode: input.mode, // undefined defaults to 'execute' in AgentManager
+ });
+ }),
+ ```
+
+ npm run build passes
+ spawnAgent procedure accepts mode parameter
+
+
+
+ Task 2: Add spawnArchitect convenience procedures
+ src/trpc/router.ts
+
+Add architect-specific spawn procedures:
+
+```typescript
+// Spawn architect in discuss mode
+spawnArchitectDiscuss: publicProcedure
+ .input(z.object({
+ name: z.string().min(1),
+ initiativeId: z.string().min(1),
+ context: z.string().optional(), // Initial context about what to discuss
+ }))
+ .mutation(async ({ ctx, input }) => {
+ const agentManager = requireAgentManager(ctx);
+ const initiativeRepo = requireInitiativeRepository(ctx);
+
+ // Verify initiative exists
+ const initiative = await initiativeRepo.findById(input.initiativeId);
+ if (!initiative) {
+ throw new TRPCError({
+ code: 'NOT_FOUND',
+ message: `Initiative '${input.initiativeId}' not found`,
+ });
+ }
+
+ const prompt = buildDiscussPrompt(initiative, input.context);
+
+ return agentManager.spawn({
+ name: input.name,
+ taskId: input.initiativeId, // Use initiative ID as task reference
+ prompt,
+ mode: 'discuss',
+ });
+ }),
+
+// Spawn architect in breakdown mode
+spawnArchitectBreakdown: publicProcedure
+ .input(z.object({
+ name: z.string().min(1),
+ initiativeId: z.string().min(1),
+ contextSummary: z.string().optional(), // Summary from discuss phase
+ }))
+ .mutation(async ({ ctx, input }) => {
+ const agentManager = requireAgentManager(ctx);
+ const initiativeRepo = requireInitiativeRepository(ctx);
+
+ const initiative = await initiativeRepo.findById(input.initiativeId);
+ if (!initiative) {
+ throw new TRPCError({
+ code: 'NOT_FOUND',
+ message: `Initiative '${input.initiativeId}' not found`,
+ });
+ }
+
+ const prompt = buildBreakdownPrompt(initiative, input.contextSummary);
+
+ return agentManager.spawn({
+ name: input.name,
+ taskId: input.initiativeId,
+ prompt,
+ mode: 'breakdown',
+ });
+ }),
+```
+
+Add helper functions above the router definition:
+```typescript
+function buildDiscussPrompt(initiative: Initiative, context?: string): string {
+ return `You are an Architect agent in discuss mode.
+
+Initiative: ${initiative.name}
+${initiative.description ? `Description: ${initiative.description}` : ''}
+${context ? `\nContext: ${context}` : ''}
+
+Your task is to ask clarifying questions to understand the requirements better.
+Ask questions about:
+- User journeys and workflows
+- Technical constraints and preferences
+- Edge cases and error handling
+- Integration points
+
+When you have enough information, output status: "context_complete" with your decisions.`;
+}
+
+function buildBreakdownPrompt(initiative: Initiative, contextSummary?: string): string {
+ return `You are an Architect agent in breakdown mode.
+
+Initiative: ${initiative.name}
+${initiative.description ? `Description: ${initiative.description}` : ''}
+${contextSummary ? `\nContext from discussion:\n${contextSummary}` : ''}
+
+Your task is to break this initiative into phases.
+Each phase should be:
+- A coherent unit of work
+- Deliverable independently
+- Clear dependencies on prior phases
+
+Output status: "breakdown_complete" with an array of phases.`;
+}
+```
+
+ npm run build passes
+ Architect spawn procedures with mode-specific prompts added
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds without errors
+- [ ] npm test passes
+- [ ] spawnAgent accepts mode parameter
+- [ ] spawnArchitectDiscuss spawns agent in discuss mode
+- [ ] spawnArchitectBreakdown spawns agent in breakdown mode
+- [ ] Both architect procedures validate initiative exists
+
+
+
+
+- All tasks completed
+- Architect workflow has dedicated spawn procedures
+- Mode-specific prompts guide agent behavior
+- Initiative validation prevents orphaned agents
+
+
+
diff --git a/.planning/phases/11-architect-agent/11-06-PLAN.md b/.planning/phases/11-architect-agent/11-06-PLAN.md
new file mode 100644
index 0000000..dd1fe2a
--- /dev/null
+++ b/.planning/phases/11-architect-agent/11-06-PLAN.md
@@ -0,0 +1,240 @@
+---
+phase: 11-architect-agent
+plan: 06
+type: execute
+wave: 3
+depends_on: ["11-04", "11-05"]
+files_modified:
+ - src/cli/index.ts
+autonomous: true
+---
+
+
+Add CLI commands for initiative management and architect workflow.
+
+Purpose: Enable users to create initiatives, list them, and spawn architect agents via the CLI.
+
+Output: CLI commands for `cw initiative` and `cw architect` command groups.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Depends on tRPC procedures
+@.planning/phases/11-architect-agent/11-04-SUMMARY.md
+@.planning/phases/11-architect-agent/11-05-SUMMARY.md
+
+# CLI reference
+@src/cli/index.ts
+
+
+
+
+
+ Task 1: Add initiative CLI commands
+ src/cli/index.ts
+
+Add initiative command group following existing patterns (agent commands):
+
+```typescript
+// cw initiative
+const initiativeCommand = program
+ .command('initiative')
+ .description('Manage initiatives');
+
+// cw initiative create
+initiativeCommand
+ .command('create ')
+ .description('Create a new initiative')
+ .option('-d, --description ', 'Initiative description')
+ .action(async (name: string, options: { description?: string }) => {
+ const client = createClient();
+ try {
+ const initiative = await client.createInitiative.mutate({
+ name,
+ description: options.description,
+ });
+ console.log(`Created initiative: ${initiative.id}`);
+ console.log(` Name: ${initiative.name}`);
+ if (initiative.description) {
+ console.log(` Description: ${initiative.description}`);
+ }
+ } catch (error) {
+ handleError(error);
+ }
+ });
+
+// cw initiative list
+initiativeCommand
+ .command('list')
+ .description('List all initiatives')
+ .option('-s, --status ', 'Filter by status (active, completed, archived)')
+ .action(async (options: { status?: 'active' | 'completed' | 'archived' }) => {
+ const client = createClient();
+ try {
+ const initiatives = await client.listInitiatives.query(
+ options.status ? { status: options.status } : undefined
+ );
+ if (initiatives.length === 0) {
+ console.log('No initiatives found');
+ return;
+ }
+ for (const init of initiatives) {
+ console.log(`${init.id} ${init.status.padEnd(10)} ${init.name}`);
+ }
+ } catch (error) {
+ handleError(error);
+ }
+ });
+
+// cw initiative get
+initiativeCommand
+ .command('get ')
+ .description('Get initiative details')
+ .action(async (id: string) => {
+ const client = createClient();
+ try {
+ const initiative = await client.getInitiative.query({ id });
+ console.log(`ID: ${initiative.id}`);
+ console.log(`Name: ${initiative.name}`);
+ console.log(`Status: ${initiative.status}`);
+ if (initiative.description) {
+ console.log(`Description: ${initiative.description}`);
+ }
+ console.log(`Created: ${initiative.createdAt.toISOString()}`);
+ } catch (error) {
+ handleError(error);
+ }
+ });
+```
+
+ npm run build passes, cw initiative --help shows commands
+ Initiative CLI commands added (create, list, get)
+
+
+
+ Task 2: Add architect CLI commands
+ src/cli/index.ts
+
+Add architect command group:
+
+```typescript
+// cw architect
+const architectCommand = program
+ .command('architect')
+ .description('Architect agent workflow');
+
+// cw architect discuss
+architectCommand
+ .command('discuss ')
+ .description('Start discussion phase for an initiative')
+ .requiredOption('--name ', 'Agent name')
+ .option('-c, --context ', 'Initial context')
+ .action(async (initiativeId: string, options: { name: string; context?: string }) => {
+ const client = createClient();
+ try {
+ const agent = await client.spawnArchitectDiscuss.mutate({
+ name: options.name,
+ initiativeId,
+ context: options.context,
+ });
+ console.log(`Started architect agent in discuss mode`);
+ console.log(` Agent: ${agent.name} (${agent.id})`);
+ console.log(` Mode: ${agent.mode}`);
+ console.log(` Initiative: ${initiativeId}`);
+ } catch (error) {
+ handleError(error);
+ }
+ });
+
+// cw architect breakdown
+architectCommand
+ .command('breakdown ')
+ .description('Start breakdown phase for an initiative')
+ .requiredOption('--name ', 'Agent name')
+ .option('-s, --summary ', 'Context summary from discuss phase')
+ .action(async (initiativeId: string, options: { name: string; summary?: string }) => {
+ const client = createClient();
+ try {
+ const agent = await client.spawnArchitectBreakdown.mutate({
+ name: options.name,
+ initiativeId,
+ contextSummary: options.summary,
+ });
+ console.log(`Started architect agent in breakdown mode`);
+ console.log(` Agent: ${agent.name} (${agent.id})`);
+ console.log(` Mode: ${agent.mode}`);
+ console.log(` Initiative: ${initiativeId}`);
+ } catch (error) {
+ handleError(error);
+ }
+ });
+```
+
+ npm run build passes, cw architect --help shows commands
+ Architect CLI commands added (discuss, breakdown)
+
+
+
+ Task 3: Add phase list command
+ src/cli/index.ts
+
+Add phase listing under initiative or as separate command:
+
+```typescript
+// cw initiative phases
+initiativeCommand
+ .command('phases ')
+ .description('List phases for an initiative')
+ .action(async (initiativeId: string) => {
+ const client = createClient();
+ try {
+ const phases = await client.listPhases.query({ initiativeId });
+ if (phases.length === 0) {
+ console.log('No phases found');
+ return;
+ }
+ for (const phase of phases) {
+ console.log(`${phase.number.toString().padStart(2)}. ${phase.name} [${phase.status}]`);
+ if (phase.description) {
+ console.log(` ${phase.description}`);
+ }
+ }
+ } catch (error) {
+ handleError(error);
+ }
+ });
+```
+
+ npm run build passes
+ Phase listing command added
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds without errors
+- [ ] cw initiative --help shows: create, list, get, phases
+- [ ] cw architect --help shows: discuss, breakdown
+- [ ] Commands follow existing CLI patterns (error handling, output format)
+
+
+
+
+- All tasks completed
+- Initiative CRUD available via CLI
+- Architect workflow accessible via CLI
+- Phase listing works for initiatives
+
+
+
diff --git a/.planning/phases/11-architect-agent/11-07-PLAN.md b/.planning/phases/11-architect-agent/11-07-PLAN.md
new file mode 100644
index 0000000..9ce9dd9
--- /dev/null
+++ b/.planning/phases/11-architect-agent/11-07-PLAN.md
@@ -0,0 +1,350 @@
+---
+phase: 11-architect-agent
+plan: 07
+type: execute
+wave: 4
+depends_on: ["11-01", "11-02", "11-03"]
+files_modified:
+ - src/agent/mock-manager.test.ts
+ - src/db/repositories/initiative-repository.test.ts
+ - src/db/repositories/phase-repository.test.ts
+autonomous: true
+---
+
+
+Add unit tests for mode schemas, MockAgentManager modes, and new repositories.
+
+Purpose: Ensure mode-specific functionality works correctly before E2E testing.
+
+Output: Test coverage for agent modes, initiative repository, and phase repository.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Test patterns
+@src/agent/mock-manager.test.ts
+@src/db/repositories/drizzle-task-repository.test.ts
+
+
+
+
+
+ Task 1: Add MockAgentManager mode tests
+ src/agent/mock-manager.test.ts
+
+Add test suite for mode functionality:
+
+```typescript
+describe('agent modes', () => {
+ it('should spawn agent with default execute mode', async () => {
+ const agent = await manager.spawn({
+ name: 'exec-agent',
+ taskId: 't1',
+ prompt: 'test',
+ });
+ expect(agent.mode).toBe('execute');
+ });
+
+ it('should spawn agent in discuss mode', async () => {
+ manager.setScenario('discuss-agent', {
+ status: 'context_complete',
+ delay: 0,
+ decisions: [{ topic: 'Auth', decision: 'JWT', reason: 'Standard' }],
+ summary: 'Auth discussion complete',
+ });
+
+ const agent = await manager.spawn({
+ name: 'discuss-agent',
+ taskId: 't1',
+ prompt: 'discuss auth',
+ mode: 'discuss',
+ });
+
+ expect(agent.mode).toBe('discuss');
+ });
+
+ it('should spawn agent in breakdown mode', async () => {
+ manager.setScenario('breakdown-agent', {
+ status: 'breakdown_complete',
+ delay: 0,
+ phases: [
+ { number: 1, name: 'Foundation', description: 'Core setup' },
+ { number: 2, name: 'Features', description: 'Main features' },
+ ],
+ });
+
+ const agent = await manager.spawn({
+ name: 'breakdown-agent',
+ taskId: 't1',
+ prompt: 'breakdown work',
+ mode: 'breakdown',
+ });
+
+ expect(agent.mode).toBe('breakdown');
+ });
+
+ it('should emit stopped event with context_complete reason', async () => {
+ manager.setScenario('discuss-done', {
+ status: 'context_complete',
+ delay: 0,
+ decisions: [],
+ summary: 'Done',
+ });
+
+ await manager.spawn({
+ name: 'discuss-done',
+ taskId: 't1',
+ prompt: 'test',
+ mode: 'discuss',
+ });
+ await vi.runAllTimersAsync();
+
+ const stopped = eventBus.emittedEvents.find(e => e.type === 'agent:stopped');
+ expect(stopped?.payload.reason).toBe('context_complete');
+ });
+
+ it('should emit stopped event with breakdown_complete reason', async () => {
+ manager.setScenario('breakdown-done', {
+ status: 'breakdown_complete',
+ delay: 0,
+ phases: [],
+ });
+
+ await manager.spawn({
+ name: 'breakdown-done',
+ taskId: 't1',
+ prompt: 'test',
+ mode: 'breakdown',
+ });
+ await vi.runAllTimersAsync();
+
+ const stopped = eventBus.emittedEvents.find(e => e.type === 'agent:stopped');
+ expect(stopped?.payload.reason).toBe('breakdown_complete');
+ });
+});
+```
+
+ npm test src/agent/mock-manager.test.ts passes
+ Mode tests added for MockAgentManager
+
+
+
+ Task 2: Add InitiativeRepository tests
+ src/db/repositories/initiative-repository.test.ts
+
+Create test file following DrizzleTaskRepository test patterns:
+
+```typescript
+import { describe, it, expect, beforeEach, afterEach } from 'vitest';
+import { DrizzleInitiativeRepository } from './drizzle-initiative-repository.js';
+import { createTestDatabase, cleanupTestDatabase } from '../test-utils.js';
+
+describe('DrizzleInitiativeRepository', () => {
+ let repository: DrizzleInitiativeRepository;
+ let cleanup: () => Promise;
+
+ beforeEach(async () => {
+ const { db, cleanup: c } = await createTestDatabase();
+ cleanup = c;
+ repository = new DrizzleInitiativeRepository(db);
+ });
+
+ afterEach(async () => {
+ await cleanup();
+ });
+
+ describe('create', () => {
+ it('should create initiative with generated id', async () => {
+ const initiative = await repository.create({
+ name: 'Test Initiative',
+ description: 'Test description',
+ status: 'active',
+ });
+
+ expect(initiative.id).toBeDefined();
+ expect(initiative.name).toBe('Test Initiative');
+ expect(initiative.status).toBe('active');
+ });
+
+ it('should set timestamps on create', async () => {
+ const initiative = await repository.create({
+ name: 'Test',
+ status: 'active',
+ });
+
+ expect(initiative.createdAt).toBeInstanceOf(Date);
+ expect(initiative.updatedAt).toBeInstanceOf(Date);
+ });
+ });
+
+ describe('findById', () => {
+ it('should find existing initiative', async () => {
+ const created = await repository.create({ name: 'Find Me', status: 'active' });
+ const found = await repository.findById(created.id);
+ expect(found).not.toBeNull();
+ expect(found?.name).toBe('Find Me');
+ });
+
+ it('should return null for non-existent id', async () => {
+ const found = await repository.findById('non-existent');
+ expect(found).toBeNull();
+ });
+ });
+
+ describe('findByStatus', () => {
+ it('should filter by status', async () => {
+ await repository.create({ name: 'Active 1', status: 'active' });
+ await repository.create({ name: 'Active 2', status: 'active' });
+ await repository.create({ name: 'Completed', status: 'completed' });
+
+ const active = await repository.findByStatus('active');
+ expect(active).toHaveLength(2);
+
+ const completed = await repository.findByStatus('completed');
+ expect(completed).toHaveLength(1);
+ });
+ });
+
+ describe('update', () => {
+ it('should update initiative fields', async () => {
+ const created = await repository.create({ name: 'Original', status: 'active' });
+ const updated = await repository.update(created.id, { name: 'Updated' });
+
+ expect(updated.name).toBe('Updated');
+ expect(updated.updatedAt.getTime()).toBeGreaterThan(created.updatedAt.getTime());
+ });
+ });
+});
+```
+
+Note: If createTestDatabase doesn't exist, create a simple test utility or use in-memory SQLite.
+
+ npm test src/db/repositories/initiative-repository.test.ts passes
+ Initiative repository tests added
+
+
+
+ Task 3: Add PhaseRepository tests
+ src/db/repositories/phase-repository.test.ts
+
+Create test file:
+
+```typescript
+import { describe, it, expect, beforeEach, afterEach } from 'vitest';
+import { DrizzlePhaseRepository } from './drizzle-phase-repository.js';
+import { DrizzleInitiativeRepository } from './drizzle-initiative-repository.js';
+import { createTestDatabase, cleanupTestDatabase } from '../test-utils.js';
+
+describe('DrizzlePhaseRepository', () => {
+ let phaseRepo: DrizzlePhaseRepository;
+ let initRepo: DrizzleInitiativeRepository;
+ let initiativeId: string;
+ let cleanup: () => Promise;
+
+ beforeEach(async () => {
+ const { db, cleanup: c } = await createTestDatabase();
+ cleanup = c;
+ phaseRepo = new DrizzlePhaseRepository(db);
+ initRepo = new DrizzleInitiativeRepository(db);
+
+ // Create parent initiative
+ const init = await initRepo.create({ name: 'Test Initiative', status: 'active' });
+ initiativeId = init.id;
+ });
+
+ afterEach(async () => {
+ await cleanup();
+ });
+
+ describe('create', () => {
+ it('should create phase with generated id', async () => {
+ const phase = await phaseRepo.create({
+ initiativeId,
+ number: 1,
+ name: 'Phase 1',
+ description: 'First phase',
+ status: 'pending',
+ });
+
+ expect(phase.id).toBeDefined();
+ expect(phase.number).toBe(1);
+ expect(phase.name).toBe('Phase 1');
+ });
+ });
+
+ describe('findByInitiativeId', () => {
+ it('should return phases ordered by number', async () => {
+ await phaseRepo.create({ initiativeId, number: 3, name: 'Phase 3', status: 'pending' });
+ await phaseRepo.create({ initiativeId, number: 1, name: 'Phase 1', status: 'pending' });
+ await phaseRepo.create({ initiativeId, number: 2, name: 'Phase 2', status: 'pending' });
+
+ const phases = await phaseRepo.findByInitiativeId(initiativeId);
+
+ expect(phases).toHaveLength(3);
+ expect(phases[0].number).toBe(1);
+ expect(phases[1].number).toBe(2);
+ expect(phases[2].number).toBe(3);
+ });
+ });
+
+ describe('getNextNumber', () => {
+ it('should return 1 for empty initiative', async () => {
+ const next = await phaseRepo.getNextNumber(initiativeId);
+ expect(next).toBe(1);
+ });
+
+ it('should return max + 1', async () => {
+ await phaseRepo.create({ initiativeId, number: 1, name: 'P1', status: 'pending' });
+ await phaseRepo.create({ initiativeId, number: 2, name: 'P2', status: 'pending' });
+
+ const next = await phaseRepo.getNextNumber(initiativeId);
+ expect(next).toBe(3);
+ });
+ });
+
+ describe('findByNumber', () => {
+ it('should find phase by initiative and number', async () => {
+ await phaseRepo.create({ initiativeId, number: 1, name: 'Phase 1', status: 'pending' });
+
+ const found = await phaseRepo.findByNumber(initiativeId, 1);
+ expect(found).not.toBeNull();
+ expect(found?.name).toBe('Phase 1');
+ });
+ });
+});
+```
+
+ npm test src/db/repositories/phase-repository.test.ts passes
+ Phase repository tests added
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm test passes for all new test files
+- [ ] Mode tests cover execute, discuss, breakdown
+- [ ] Repository tests cover CRUD operations
+- [ ] All existing tests still pass
+
+
+
+
+- All tasks completed
+- MockAgentManager modes tested
+- Initiative repository CRUD tested
+- Phase repository CRUD tested
+- getNextNumber edge cases tested
+
+
+
diff --git a/.planning/phases/11-architect-agent/11-08-PLAN.md b/.planning/phases/11-architect-agent/11-08-PLAN.md
new file mode 100644
index 0000000..cc9a407
--- /dev/null
+++ b/.planning/phases/11-architect-agent/11-08-PLAN.md
@@ -0,0 +1,361 @@
+---
+phase: 11-architect-agent
+plan: 08
+type: execute
+wave: 4
+depends_on: ["11-05", "11-06", "11-07"]
+files_modified:
+ - src/test/harness.ts
+ - src/test/e2e/architect-workflow.test.ts
+autonomous: true
+---
+
+
+Add TestHarness support for architect modes and E2E tests for the discuss→breakdown workflow.
+
+Purpose: Validate the complete architect workflow from discussion through phase creation.
+
+Output: E2E tests proving architect mode switching and phase persistence work.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Test infrastructure
+@src/test/harness.ts
+@src/test/e2e/recovery-scenarios.test.ts
+
+# Prior plan context
+@.planning/phases/11-architect-agent/11-07-SUMMARY.md
+
+
+
+
+
+ Task 1: Add TestHarness helpers for architect modes
+ src/test/harness.ts
+
+Add convenience methods for architect mode scenarios:
+
+```typescript
+/**
+ * Set up scenario where architect completes discussion with decisions
+ */
+setArchitectDiscussComplete(
+ agentName: string,
+ decisions: Array<{ topic: string; decision: string; reason: string }>,
+ summary: string
+): void {
+ this.mockAgentManager.setScenario(agentName, {
+ status: 'context_complete',
+ delay: 0,
+ decisions,
+ summary,
+ });
+}
+
+/**
+ * Set up scenario where architect needs more questions in discuss mode
+ */
+setArchitectDiscussQuestions(
+ agentName: string,
+ questions: Array<{ id: string; question: string; options?: Array<{ label: string }> }>
+): void {
+ this.mockAgentManager.setScenario(agentName, {
+ status: 'questions',
+ delay: 0,
+ questions,
+ });
+}
+
+/**
+ * Set up scenario where architect completes breakdown with phases
+ */
+setArchitectBreakdownComplete(
+ agentName: string,
+ phases: Array<{ number: number; name: string; description: string }>
+): void {
+ this.mockAgentManager.setScenario(agentName, {
+ status: 'breakdown_complete',
+ delay: 0,
+ phases,
+ });
+}
+
+/**
+ * Get initiative by ID through tRPC
+ */
+async getInitiative(id: string): Promise {
+ try {
+ return await this.caller.getInitiative({ id });
+ } catch {
+ return null;
+ }
+}
+
+/**
+ * Get phases for initiative through tRPC
+ */
+async getPhases(initiativeId: string): Promise {
+ return this.caller.listPhases({ initiativeId });
+}
+
+/**
+ * Create initiative through tRPC
+ */
+async createInitiative(name: string, description?: string): Promise {
+ return this.caller.createInitiative({ name, description });
+}
+
+/**
+ * Create phases from breakdown output through tRPC
+ */
+async createPhasesFromBreakdown(
+ initiativeId: string,
+ phases: Array<{ number: number; name: string; description: string }>
+): Promise {
+ return this.caller.createPhasesFromBreakdown({ initiativeId, phases });
+}
+```
+
+Update imports as needed for Initiative and Phase types.
+
+ npm run build passes
+ TestHarness has architect mode helpers
+
+
+
+ Task 2: Add E2E test for discuss mode
+ src/test/e2e/architect-workflow.test.ts
+
+Create new E2E test file:
+
+```typescript
+import { describe, it, expect, beforeEach, afterEach } from 'vitest';
+import { TestHarness } from '../harness.js';
+
+describe('Architect Workflow E2E', () => {
+ let harness: TestHarness;
+
+ beforeEach(async () => {
+ harness = await TestHarness.create();
+ });
+
+ afterEach(async () => {
+ await harness.cleanup();
+ });
+
+ describe('discuss mode', () => {
+ it('should spawn architect in discuss mode and complete with decisions', async () => {
+ // Create initiative
+ const initiative = await harness.createInitiative('Auth System', 'User authentication');
+
+ // Set up discuss completion scenario
+ harness.setArchitectDiscussComplete('auth-discuss', [
+ { topic: 'Auth Method', decision: 'JWT', reason: 'Stateless, scalable' },
+ { topic: 'Token Storage', decision: 'httpOnly cookie', reason: 'XSS protection' },
+ ], 'Auth approach decided');
+
+ // Spawn architect in discuss mode
+ const agent = await harness.caller.spawnArchitectDiscuss({
+ name: 'auth-discuss',
+ initiativeId: initiative.id,
+ });
+
+ expect(agent.mode).toBe('discuss');
+
+ // Wait for completion
+ await harness.advanceTimers();
+
+ // Verify agent stopped with context_complete
+ const events = harness.getEmittedEvents('agent:stopped');
+ expect(events).toHaveLength(1);
+ expect(events[0].payload.reason).toBe('context_complete');
+ });
+
+ it('should pause on questions and resume with answers', async () => {
+ const initiative = await harness.createInitiative('Auth System');
+
+ // First, agent asks questions
+ harness.setArchitectDiscussQuestions('auth-discuss', [
+ { id: 'q1', question: 'JWT or Session?', options: [{ label: 'JWT' }, { label: 'Session' }] },
+ { id: 'q2', question: 'OAuth providers?' },
+ ]);
+
+ const agent = await harness.caller.spawnArchitectDiscuss({
+ name: 'auth-discuss',
+ initiativeId: initiative.id,
+ });
+
+ await harness.advanceTimers();
+
+ // Agent should be waiting
+ const waitingAgent = await harness.caller.getAgent({ name: 'auth-discuss' });
+ expect(waitingAgent?.status).toBe('waiting_for_input');
+
+ // Get pending questions
+ const pending = await harness.mockAgentManager.getPendingQuestions(agent.id);
+ expect(pending?.questions).toHaveLength(2);
+
+ // Now set up completion scenario for after resume
+ harness.setArchitectDiscussComplete('auth-discuss', [
+ { topic: 'Auth', decision: 'JWT', reason: 'User chose' },
+ ], 'Complete');
+
+ // Resume with answers
+ await harness.caller.resumeAgent({
+ name: 'auth-discuss',
+ answers: { q1: 'JWT', q2: 'Google, GitHub' },
+ });
+
+ await harness.advanceTimers();
+
+ // Should complete
+ const finalAgent = await harness.caller.getAgent({ name: 'auth-discuss' });
+ expect(finalAgent?.status).toBe('idle');
+ });
+ });
+});
+```
+
+ npm test src/test/e2e/architect-workflow.test.ts passes
+ Discuss mode E2E tests added
+
+
+
+ Task 3: Add E2E test for breakdown mode and phase persistence
+ src/test/e2e/architect-workflow.test.ts
+
+Add breakdown tests to the same file:
+
+```typescript
+describe('breakdown mode', () => {
+ it('should spawn architect in breakdown mode and create phases', async () => {
+ const initiative = await harness.createInitiative('Auth System');
+
+ // Set up breakdown completion
+ harness.setArchitectBreakdownComplete('auth-breakdown', [
+ { number: 1, name: 'Database Setup', description: 'User table and auth schema' },
+ { number: 2, name: 'JWT Implementation', description: 'Token generation and validation' },
+ { number: 3, name: 'Protected Routes', description: 'Middleware and route guards' },
+ ]);
+
+ const agent = await harness.caller.spawnArchitectBreakdown({
+ name: 'auth-breakdown',
+ initiativeId: initiative.id,
+ });
+
+ expect(agent.mode).toBe('breakdown');
+
+ await harness.advanceTimers();
+
+ // Verify stopped with breakdown_complete
+ const events = harness.getEmittedEvents('agent:stopped');
+ expect(events).toHaveLength(1);
+ expect(events[0].payload.reason).toBe('breakdown_complete');
+ });
+
+ it('should persist phases from breakdown output', async () => {
+ const initiative = await harness.createInitiative('Auth System');
+
+ const phasesData = [
+ { number: 1, name: 'Foundation', description: 'Core setup' },
+ { number: 2, name: 'Features', description: 'Main features' },
+ ];
+
+ // Persist phases (simulating what would happen after breakdown)
+ const created = await harness.createPhasesFromBreakdown(initiative.id, phasesData);
+
+ expect(created).toHaveLength(2);
+ expect(created[0].number).toBe(1);
+ expect(created[1].number).toBe(2);
+
+ // Verify retrieval
+ const phases = await harness.getPhases(initiative.id);
+ expect(phases).toHaveLength(2);
+ expect(phases[0].name).toBe('Foundation');
+ expect(phases[1].name).toBe('Features');
+ });
+});
+
+describe('full workflow', () => {
+ it('should complete discuss → breakdown → phases workflow', async () => {
+ // 1. Create initiative
+ const initiative = await harness.createInitiative('Full Workflow Test');
+
+ // 2. Discuss phase
+ harness.setArchitectDiscussComplete('discuss-agent', [
+ { topic: 'Scope', decision: 'MVP only', reason: 'Time constraint' },
+ ], 'Scope defined');
+
+ await harness.caller.spawnArchitectDiscuss({
+ name: 'discuss-agent',
+ initiativeId: initiative.id,
+ });
+ await harness.advanceTimers();
+
+ // 3. Breakdown phase
+ harness.setArchitectBreakdownComplete('breakdown-agent', [
+ { number: 1, name: 'Core', description: 'Core functionality' },
+ { number: 2, name: 'Polish', description: 'UI and UX' },
+ ]);
+
+ await harness.caller.spawnArchitectBreakdown({
+ name: 'breakdown-agent',
+ initiativeId: initiative.id,
+ contextSummary: 'MVP scope defined',
+ });
+ await harness.advanceTimers();
+
+ // 4. Persist phases
+ await harness.createPhasesFromBreakdown(initiative.id, [
+ { number: 1, name: 'Core', description: 'Core functionality' },
+ { number: 2, name: 'Polish', description: 'UI and UX' },
+ ]);
+
+ // 5. Verify final state
+ const phases = await harness.getPhases(initiative.id);
+ expect(phases).toHaveLength(2);
+
+ // Both agents should be idle
+ const agents = await harness.caller.listAgents();
+ expect(agents.filter(a => a.status === 'idle')).toHaveLength(2);
+ });
+});
+```
+
+ npm test src/test/e2e/architect-workflow.test.ts passes
+ Full architect workflow E2E tests added
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds
+- [ ] npm test passes all tests including new E2E tests
+- [ ] Discuss mode completion tested
+- [ ] Discuss Q&A flow tested
+- [ ] Breakdown mode completion tested
+- [ ] Phase persistence tested
+- [ ] Full workflow tested
+
+
+
+
+- All tasks completed
+- TestHarness has architect-specific helpers
+- E2E tests cover discuss → breakdown → persist workflow
+- All existing tests still pass
+
+
+