diff --git a/.planning/phases/05-task-dispatch/05-01-PLAN.md b/.planning/phases/05-task-dispatch/05-01-PLAN.md
new file mode 100644
index 0000000..2bf1c08
--- /dev/null
+++ b/.planning/phases/05-task-dispatch/05-01-PLAN.md
@@ -0,0 +1,116 @@
+---
+phase: 05-task-dispatch
+plan: 01
+type: execute
+wave: 1
+depends_on: []
+files_modified: [src/db/schema.ts, src/db/repositories/message-repository.ts, src/db/repositories/drizzle/message.ts, src/db/repositories/drizzle/message.test.ts, src/db/repositories/index.ts, src/db/repositories/drizzle/index.ts]
+autonomous: true
+---
+
+
+Add message schema and repository for persisting agent questions.
+
+Purpose: AGENT-06 requires agents to surface questions to users. When an agent pauses on AskUserQuestion, the question needs to persist in the database so users can query pending messages and respond later.
+Output: messages table, MessageRepository port/adapter with full CRUD and tests.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+@src/db/schema.ts
+@src/db/repositories/task-repository.ts
+@src/db/repositories/drizzle/task.ts
+@src/db/repositories/drizzle/agent.ts
+@src/events/types.ts
+
+
+
+
+
+ Task 1: Add messages table to schema
+ src/db/schema.ts
+
+Add messages table after agents table. Schema:
+- id: text primary key
+- agentId: text NOT NULL foreign key to agents.id with SET NULL on delete (message persists even if agent deleted)
+- type: text enum ['question', 'info', 'error'] NOT NULL default 'question'
+- content: text NOT NULL (the question or message text)
+- status: text enum ['pending', 'read', 'responded'] NOT NULL default 'pending'
+- response: text nullable (user's response when status is 'responded')
+- createdAt: integer timestamp NOT NULL
+- updatedAt: integer timestamp NOT NULL
+
+Add relations: message belongs to agent (nullable after delete).
+Export Message and NewMessage types.
+
+Follow existing patterns: use sqliteTable, relations, InferSelectModel/InferInsertModel.
+
+ npm run build passes, no TypeScript errors
+ messages table in schema with types exported
+
+
+
+ Task 2: Create MessageRepository port and adapter
+ src/db/repositories/message-repository.ts, src/db/repositories/drizzle/message.ts, src/db/repositories/drizzle/message.test.ts, src/db/repositories/index.ts, src/db/repositories/drizzle/index.ts
+
+Create MessageRepository following TaskRepository pattern exactly:
+
+1. Port interface (message-repository.ts):
+ - CreateMessageData type (omit id, createdAt, updatedAt)
+ - UpdateMessageData type (partial of create data)
+ - MessageRepository interface with:
+ - create(data: CreateMessageData): Promise
+ - findById(id: string): Promise
+ - findByAgentId(agentId: string): Promise
+ - findPending(): Promise (status = 'pending')
+ - update(id: string, data: UpdateMessageData): Promise
+ - delete(id: string): Promise
+
+2. Drizzle adapter (drizzle/message.ts):
+ - DrizzleMessageRepository class implementing port
+ - Use nanoid for id generation
+ - Fetch after insert to get schema defaults
+ - Order by createdAt DESC for lists
+
+3. Tests (drizzle/message.test.ts):
+ - Use createTestDatabase helper
+ - Test create, findById, findByAgentId, findPending, update, delete
+ - Test pending filter returns only pending messages
+ - Test response field update when marking as responded
+
+4. Re-export from index files (same pattern as AgentRepository)
+
+ npm test -- src/db/repositories/drizzle/message.test.ts passes
+ MessageRepository port/adapter with passing tests
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds
+- [ ] npm test passes all tests including new message tests
+- [ ] messages table accessible via DrizzleMessageRepository
+- [ ] findPending returns only pending messages
+
+
+
+
+- messages table added to schema with proper types
+- MessageRepository port interface defined
+- DrizzleMessageRepository adapter implemented
+- All tests pass
+- Exports wired up in index files
+
+
+
diff --git a/.planning/phases/05-task-dispatch/05-02-PLAN.md b/.planning/phases/05-task-dispatch/05-02-PLAN.md
new file mode 100644
index 0000000..0894b42
--- /dev/null
+++ b/.planning/phases/05-task-dispatch/05-02-PLAN.md
@@ -0,0 +1,122 @@
+---
+phase: 05-task-dispatch
+plan: 02
+type: execute
+wave: 1
+depends_on: []
+files_modified: [src/trpc/router.ts, src/trpc/context.ts, src/cli/index.ts]
+autonomous: true
+---
+
+
+Add task visibility via tRPC and CLI.
+
+Purpose: TASK-01 requires users to see status of all tasks at a glance. Expose existing TaskRepository through tRPC endpoints and CLI commands for task listing and status viewing.
+Output: tRPC task procedures, CLI `cw task list` and `cw task get` commands.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+@src/trpc/router.ts
+@src/trpc/context.ts
+@src/cli/index.ts
+@src/db/repositories/task-repository.ts
+@src/db/schema.ts
+
+
+
+
+
+ Task 1: Add task tRPC procedures
+ src/trpc/router.ts, src/trpc/context.ts
+
+1. Add TaskRepository to TRPCContext (optional, same pattern as agentManager):
+ - Add taskRepository?: TaskRepository to context type
+ - Add requireTaskRepository helper function
+
+2. Add task procedures to appRouter:
+
+ listTasks: publicProcedure
+ .input(z.object({ planId: z.string().optional() }))
+ .query(...)
+ - If planId provided, return tasks for that plan (ordered by order field)
+ - If no planId, return all tasks (need to add findAll to TaskRepository first - OR use a simple "list all" query)
+ - Actually, for simplicity: require planId. Users query by plan.
+ - Return array of Task objects
+
+ getTask: publicProcedure
+ .input(z.object({ id: z.string() }))
+ .query(...)
+ - Return single task or throw NOT_FOUND
+
+ updateTaskStatus: publicProcedure
+ .input(z.object({
+ id: z.string(),
+ status: z.enum(['pending', 'in_progress', 'completed', 'blocked'])
+ }))
+ .mutation(...)
+ - Update task status
+ - Return updated task
+
+Follow existing patterns from agent procedures. Use Zod schemas for input validation.
+
+ npm run build passes, npm test -- src/trpc/router.test.ts passes
+ Task tRPC procedures available: listTasks, getTask, updateTaskStatus
+
+
+
+ Task 2: Add task CLI commands
+ src/cli/index.ts
+
+Add task subcommands to the existing 'task' command group:
+
+1. cw task list --plan
+ - Call listTasks tRPC procedure
+ - Display tasks as table: name, status, type, priority
+ - Show count of pending/in_progress/completed
+
+2. cw task get
+ - Call getTask tRPC procedure
+ - Display full task details: id, name, description, type, priority, status, order, timestamps
+
+3. cw task status
+ - Call updateTaskStatus tRPC procedure
+ - Validate status is one of: pending, in_progress, completed, blocked
+ - Confirm status update
+
+Replace the placeholder "not implemented" action with real commands.
+Follow existing CLI patterns (error handling, client creation, output formatting).
+
+ cw task list --plan test-id shows error (expected - no server), cw task --help shows commands
+ CLI task commands functional: list, get, status
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds
+- [ ] npm test passes
+- [ ] cw task --help shows list, get, status commands
+- [ ] Task procedures added to router
+
+
+
+
+- tRPC task procedures (listTasks, getTask, updateTaskStatus) added
+- TaskRepository optional in context (same pattern as AgentManager)
+- CLI task commands: list, get, status
+- All existing tests still pass
+
+
+
diff --git a/.planning/phases/05-task-dispatch/05-03-PLAN.md b/.planning/phases/05-task-dispatch/05-03-PLAN.md
new file mode 100644
index 0000000..b68dd47
--- /dev/null
+++ b/.planning/phases/05-task-dispatch/05-03-PLAN.md
@@ -0,0 +1,165 @@
+---
+phase: 05-task-dispatch
+plan: 03
+type: execute
+wave: 1
+depends_on: []
+files_modified: [src/dispatch/types.ts, src/dispatch/index.ts, src/events/types.ts, src/events/index.ts]
+autonomous: true
+---
+
+
+Define DispatchManager port interface and dispatch events.
+
+Purpose: TASK-04 and TASK-05 require dependency-ordered task dispatch and work queue. Define the port interface that the adapter will implement, plus domain events for dispatch lifecycle.
+Output: DispatchManager port interface, dispatch domain events, exported from dispatch module.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+@src/agent/types.ts
+@src/git/types.ts
+@src/events/types.ts
+@src/db/schema.ts
+
+
+
+
+
+ Task 1: Create DispatchManager port interface
+ src/dispatch/types.ts, src/dispatch/index.ts
+
+Create src/dispatch/ directory with types.ts and index.ts.
+
+In types.ts, define:
+
+1. QueuedTask type:
+ - taskId: string
+ - priority: 'low' | 'medium' | 'high'
+ - queuedAt: Date
+ - dependsOn: string[] (task IDs that must complete first)
+
+2. DispatchResult type:
+ - success: boolean
+ - taskId: string
+ - agentId?: string (assigned agent if dispatched)
+ - reason?: string (why dispatch failed if not success)
+
+3. DispatchManager port interface:
+ /**
+ * DispatchManager Port Interface
+ *
+ * Manages task dispatch queue with dependency ordering.
+ *
+ * Covers requirements:
+ * - TASK-04: Dependency-ordered dispatch
+ * - TASK-05: Work queue for available agents
+ */
+ interface DispatchManager {
+ /**
+ * Queue a task for dispatch.
+ * Task will be dispatched when all dependencies complete.
+ */
+ queue(taskId: string): Promise;
+
+ /**
+ * Get next dispatchable task.
+ * Returns task with all dependencies complete, highest priority first.
+ * Returns null if no tasks ready.
+ */
+ getNextDispatchable(): Promise;
+
+ /**
+ * Dispatch next available task to an agent.
+ * Finds available agent, assigns task, spawns agent.
+ * Returns dispatch result.
+ */
+ dispatchNext(): Promise;
+
+ /**
+ * Mark a task as complete.
+ * Triggers re-evaluation of dependent tasks.
+ */
+ completeTask(taskId: string): Promise;
+
+ /**
+ * Mark a task as blocked.
+ * Task will not be dispatched until unblocked.
+ */
+ blockTask(taskId: string, reason: string): Promise;
+
+ /**
+ * Get current queue state.
+ * Returns all queued tasks with their dispatch readiness.
+ */
+ getQueueState(): Promise<{
+ queued: QueuedTask[];
+ ready: QueuedTask[];
+ blocked: Array<{ taskId: string; reason: string }>;
+ }>;
+ }
+
+Export all types from index.ts.
+
+ npm run build passes, types importable from src/dispatch
+ DispatchManager port interface defined and exported
+
+
+
+ Task 2: Add dispatch domain events
+ src/events/types.ts, src/events/index.ts
+
+Add dispatch events to events/types.ts, following existing patterns:
+
+1. TaskQueuedEvent:
+ type: 'task:queued'
+ payload: { taskId: string; priority: string; dependsOn: string[] }
+
+2. TaskDispatchedEvent:
+ type: 'task:dispatched'
+ payload: { taskId: string; agentId: string; agentName: string }
+
+3. TaskCompletedEvent:
+ type: 'task:completed'
+ payload: { taskId: string; agentId: string; success: boolean; message: string }
+
+4. TaskBlockedEvent:
+ type: 'task:blocked'
+ payload: { taskId: string; reason: string; blockedBy?: string[] }
+
+Add all four to DomainEventMap union type.
+No changes needed to index.ts (types auto-exported).
+
+ npm run build passes, events compile without errors
+ Dispatch events added to DomainEventMap
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds
+- [ ] npm test passes
+- [ ] DispatchManager interface importable from src/dispatch
+- [ ] Dispatch events in DomainEventMap
+
+
+
+
+- src/dispatch/types.ts with DispatchManager interface
+- QueuedTask, DispatchResult types defined
+- Four dispatch events added to events/types.ts
+- All types properly exported
+
+
+
diff --git a/.planning/phases/05-task-dispatch/05-04-PLAN.md b/.planning/phases/05-task-dispatch/05-04-PLAN.md
new file mode 100644
index 0000000..99038b9
--- /dev/null
+++ b/.planning/phases/05-task-dispatch/05-04-PLAN.md
@@ -0,0 +1,174 @@
+---
+phase: 05-task-dispatch
+plan: 04
+type: execute
+wave: 2
+depends_on: ["05-01", "05-03"]
+files_modified: [src/dispatch/manager.ts, src/dispatch/manager.test.ts, src/dispatch/index.ts]
+autonomous: true
+---
+
+
+Implement DispatchManager adapter with dependency checking and queue management.
+
+Purpose: TASK-04 requires dependency-ordered dispatch, TASK-05 requires work queue. Implement the DispatchManager adapter that checks task dependencies before dispatch and manages the work queue.
+Output: DispatchManager adapter with dependency algorithm, queue management, and tests.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+@.planning/phases/05-task-dispatch/05-01-SUMMARY.md
+@.planning/phases/05-task-dispatch/05-03-SUMMARY.md
+
+@src/dispatch/types.ts
+@src/db/schema.ts
+@src/db/repositories/task-repository.ts
+@src/agent/types.ts
+@src/events/types.ts
+
+
+
+
+
+ Task 1: Implement dependency checking algorithm
+ src/dispatch/manager.ts
+
+Create DefaultDispatchManager class implementing DispatchManager interface.
+
+Constructor dependencies (inject via constructor):
+- taskRepository: TaskRepository
+- messageRepository: MessageRepository (from 05-01)
+- agentManager: AgentManager
+- eventBus: EventBus
+
+Implement core dependency algorithm:
+
+1. queue(taskId):
+ - Fetch task and its dependencies from task_dependencies table
+ - Add to internal queue (use Map)
+ - Emit TaskQueuedEvent
+
+2. getNextDispatchable():
+ - Get all queued tasks
+ - For each, check if ALL dependencies have status='completed'
+ - Filter to only ready tasks (all deps complete)
+ - Sort by priority (high > medium > low), then by queuedAt (oldest first)
+ - Return first or null
+
+3. completeTask(taskId):
+ - Update task status to 'completed' via taskRepository
+ - Remove from queue
+ - Emit TaskCompletedEvent
+ - Note: dependent tasks automatically become ready on next getNextDispatchable call
+
+4. blockTask(taskId, reason):
+ - Update task status to 'blocked' via taskRepository
+ - Emit TaskBlockedEvent
+
+Use simple in-memory queue (Map). Production could use persistent queue but in-memory is fine for v1.
+
+ npm run build passes
+ Dependency checking algorithm implemented
+
+
+
+ Task 2: Implement dispatchNext and queue state
+ src/dispatch/manager.ts
+
+Complete DispatchManager implementation:
+
+1. dispatchNext():
+ - Call getNextDispatchable() to get next task
+ - If null, return { success: false, taskId: '', reason: 'No dispatchable tasks' }
+ - Find available agent (status='idle') via agentManager.list()
+ - If no available agent, return { success: false, taskId, reason: 'No available agents' }
+ - Get task details from taskRepository
+ - Spawn agent with task: agentManager.spawn({ name: generateAgentName(), taskId, prompt: task.description || task.name })
+ - Update task status to 'in_progress'
+ - Emit TaskDispatchedEvent
+ - Return { success: true, taskId, agentId }
+
+2. getQueueState():
+ - Return { queued: [...allQueuedTasks], ready: [...readyTasks], blocked: [...blockedTasks] }
+ - Uses internal queue state
+
+Helper: generateAgentName():
+ - Generate unique name for agent (e.g., 'agent-${nanoid(6)}' or use Vancouver neighborhood names: 'gastown', 'yaletown', 'kitsilano', etc.)
+ - For v1: simple 'agent-${taskId.slice(0,6)}' is fine
+
+Handle edge cases:
+- Task not found: throw error
+- Circular dependencies: not checked in v1 (assume valid DAG)
+
+ npm run build passes
+ dispatchNext and getQueueState implemented
+
+
+
+ Task 3: Add tests and wire up exports
+ src/dispatch/manager.test.ts, src/dispatch/index.ts
+
+Create manager.test.ts with tests:
+
+1. Setup:
+ - Create in-memory database with createTestDatabase helper
+ - Create mock/real repositories and EventBus
+ - Create test tasks with dependencies
+
+2. Test cases:
+ - queue adds task to queue and emits event
+ - getNextDispatchable returns null when queue empty
+ - getNextDispatchable returns task when dependencies complete
+ - getNextDispatchable returns null when dependencies incomplete
+ - getNextDispatchable respects priority ordering
+ - completeTask updates status and emits event
+ - blockTask updates status and emits event
+ - dispatchNext returns failure when no tasks ready
+ - dispatchNext returns failure when no agents available
+ - getQueueState returns correct state
+
+3. Test dependency scenario:
+ - Task A (no deps)
+ - Task B (depends on A)
+ - Task C (depends on A)
+ - Queue all three
+ - Only A should be dispatchable
+ - Complete A
+ - B and C should become dispatchable
+
+Update index.ts to export DefaultDispatchManager class.
+
+ npm test -- src/dispatch/manager.test.ts passes
+ Tests pass, DispatchManager exported
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds
+- [ ] npm test passes all tests
+- [ ] Dependency ordering works correctly
+- [ ] Queue state accurately reflects task readiness
+
+
+
+
+- DefaultDispatchManager implements DispatchManager interface
+- Dependency checking prevents premature dispatch
+- Priority ordering respected
+- All dispatch events emitted correctly
+- Tests cover core scenarios
+
+
+
diff --git a/.planning/phases/05-task-dispatch/05-05-PLAN.md b/.planning/phases/05-task-dispatch/05-05-PLAN.md
new file mode 100644
index 0000000..aaedf4d
--- /dev/null
+++ b/.planning/phases/05-task-dispatch/05-05-PLAN.md
@@ -0,0 +1,174 @@
+---
+phase: 05-task-dispatch
+plan: 05
+type: execute
+wave: 3
+depends_on: ["05-02", "05-04"]
+files_modified: [src/trpc/router.ts, src/trpc/context.ts, src/cli/index.ts]
+autonomous: true
+---
+
+
+Add message and dispatch tRPC procedures and CLI commands.
+
+Purpose: Complete AGENT-06 (message visibility) and TASK-04/TASK-05 (dispatch control) with user-facing interfaces. Users can view pending agent questions and control task dispatch.
+Output: tRPC message and dispatch procedures, CLI commands for messages and dispatch.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+@.planning/phases/05-task-dispatch/05-01-SUMMARY.md
+@.planning/phases/05-task-dispatch/05-02-SUMMARY.md
+@.planning/phases/05-task-dispatch/05-04-SUMMARY.md
+
+@src/trpc/router.ts
+@src/trpc/context.ts
+@src/cli/index.ts
+@src/db/repositories/message-repository.ts
+@src/dispatch/types.ts
+
+
+
+
+
+ Task 1: Add message and dispatch tRPC procedures
+ src/trpc/router.ts, src/trpc/context.ts
+
+1. Add to TRPCContext:
+ - messageRepository?: MessageRepository
+ - dispatchManager?: DispatchManager
+ - Add requireMessageRepository and requireDispatchManager helpers
+
+2. Add message procedures to appRouter:
+
+ listMessages: publicProcedure
+ .input(z.object({ agentId: z.string().optional(), status: z.enum(['pending', 'read', 'responded']).optional() }))
+ .query(...)
+ - If agentId, filter by agent
+ - If status, filter by status
+ - Return array of Message objects
+
+ getMessage: publicProcedure
+ .input(z.object({ id: z.string() }))
+ .query(...)
+ - Return single message or throw NOT_FOUND
+
+ respondToMessage: publicProcedure
+ .input(z.object({ id: z.string(), response: z.string() }))
+ .mutation(...)
+ - Update message with response and status='responded'
+ - Return updated message
+
+3. Add dispatch procedures:
+
+ queueTask: publicProcedure
+ .input(z.object({ taskId: z.string() }))
+ .mutation(...)
+ - Call dispatchManager.queue(taskId)
+ - Return { success: true }
+
+ dispatchNext: publicProcedure
+ .mutation(...)
+ - Call dispatchManager.dispatchNext()
+ - Return DispatchResult
+
+ getQueueState: publicProcedure
+ .query(...)
+ - Call dispatchManager.getQueueState()
+ - Return queue state object
+
+ completeTask: publicProcedure
+ .input(z.object({ taskId: z.string() }))
+ .mutation(...)
+ - Call dispatchManager.completeTask(taskId)
+ - Return { success: true }
+
+ npm run build passes
+ Message and dispatch tRPC procedures added
+
+
+
+ Task 2: Add message and dispatch CLI commands
+ src/cli/index.ts
+
+1. Add message command group:
+
+ const messageCommand = program
+ .command('message')
+ .description('View agent messages and questions');
+
+ cw message list [--agent ] [--status ]
+ - Call listMessages tRPC
+ - Display as table: id (short), agent, type, content (truncated), status, createdAt
+ - Show "(pending)" count prominently
+
+ cw message read
+ - Call getMessage tRPC
+ - Display full message content
+ - If pending, show prompt to respond
+
+ cw message respond
+ - Call respondToMessage tRPC
+ - Confirm response recorded
+ - Suggest resuming agent if appropriate
+
+2. Add dispatch command group:
+
+ const dispatchCommand = program
+ .command('dispatch')
+ .description('Control task dispatch queue');
+
+ cw dispatch queue
+ - Call queueTask tRPC
+ - Confirm task queued
+
+ cw dispatch next
+ - Call dispatchNext tRPC
+ - Show result: which task dispatched to which agent, or why it failed
+
+ cw dispatch status
+ - Call getQueueState tRPC
+ - Show: queued count, ready count, blocked count
+ - List ready tasks with their priority
+
+ cw dispatch complete
+ - Call completeTask tRPC
+ - Confirm task completed
+
+Follow existing CLI patterns for error handling and output formatting.
+
+ cw message --help and cw dispatch --help show commands
+ Message and dispatch CLI commands functional
+
+
+
+
+
+Before declaring plan complete:
+- [ ] npm run build succeeds
+- [ ] npm test passes
+- [ ] cw message --help shows list, read, respond
+- [ ] cw dispatch --help shows queue, next, status, complete
+- [ ] All tRPC procedures added
+
+
+
+
+- Message tRPC procedures: listMessages, getMessage, respondToMessage
+- Dispatch tRPC procedures: queueTask, dispatchNext, getQueueState, completeTask
+- CLI message commands: list, read, respond
+- CLI dispatch commands: queue, next, status, complete
+- All requirements (AGENT-06, TASK-01, TASK-04, TASK-05) have user-facing interfaces
+
+
+