---
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
---

<objective>
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.
</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

@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
</context>

<tasks>

<task type="auto">
  <name>Task 1: Add messages table to schema</name>
  <files>src/db/schema.ts</files>
  <action>
Add messages table after agents table. Schema:
- id: text primary key
- senderType: text enum ['agent', 'user'] NOT NULL (who sent the message)
- senderId: text nullable (agent ID if senderType='agent', null for user)
- recipientType: text enum ['agent', 'user'] NOT NULL (who receives the message)
- recipientId: text nullable (agent ID if recipientType='agent', null for user)
- type: text enum ['question', 'info', 'error', 'response'] NOT NULL default 'info'
- content: text NOT NULL (the message text)
- requiresResponse: integer boolean NOT NULL default 0 (1 = expects reply, 0 = notification only)
- status: text enum ['pending', 'read', 'responded'] NOT NULL default 'pending'
- parentMessageId: text nullable foreign key to messages.id (links response to original question)
- createdAt: integer timestamp NOT NULL
- updatedAt: integer timestamp NOT NULL

Sender/recipient foreign keys reference agents.id with SET NULL on delete (messages persist).

Add relations:
- sender agent (optional)
- recipient agent (optional)
- parent message (for threading responses)
- child messages (replies to this message)

Export Message and NewMessage types.

Follow existing patterns: use sqliteTable, relations, InferSelectModel/InferInsertModel.
  </action>
  <verify>npm run build passes, no TypeScript errors</verify>
  <done>messages table in schema with types exported</done>
</task>

<task type="auto">
  <name>Task 2: Create MessageRepository port and adapter</name>
  <files>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</files>
  <action>
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<Message>
     - findById(id: string): Promise<Message | null>
     - findBySender(type: 'agent'|'user', id?: string): Promise<Message[]>
     - findByRecipient(type: 'agent'|'user', id?: string): Promise<Message[]>
     - findPendingForUser(): Promise<Message[]> (recipientType='user', status='pending')
     - findRequiringResponse(): Promise<Message[]> (requiresResponse=true, status='pending')
     - findReplies(parentMessageId: string): Promise<Message[]>
     - update(id: string, data: UpdateMessageData): Promise<Message>
     - delete(id: string): Promise<void>

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 with agent→user message (question)
   - Test create with agent→user message (notification, requiresResponse=false)
   - Test findBySender and findByRecipient
   - Test findPendingForUser returns only user-targeted pending messages
   - Test findRequiringResponse returns only messages needing response
   - Test message threading (parentMessageId linking)
   - Test update status flow: pending → read → responded

4. Re-export from index files (same pattern as AgentRepository)
  </action>
  <verify>npm test -- src/db/repositories/drizzle/message.test.ts passes</verify>
  <done>MessageRepository port/adapter with passing tests</done>
</task>

</tasks>

<verification>
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
</verification>

<success_criteria>

- messages table added to schema with proper types
- MessageRepository port interface defined
- DrizzleMessageRepository adapter implemented
- All tests pass
- Exports wired up in index files
  </success_criteria>

<output>
After completion, create `.planning/phases/05-task-dispatch/05-01-SUMMARY.md`
</output>
