diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
index eece46b..ea97161 100644
--- a/.planning/ROADMAP.md
+++ b/.planning/ROADMAP.md
@@ -294,10 +294,13 @@ Plans:
**Goal**: Message list, multi-question forms (radio/checkbox/free-text), answer submission, notifications
**Depends on**: Phase 18
**Research**: Unlikely (internal patterns, form handling from wireframes)
-**Plans**: TBD
+**Plans**: 4 plans
Plans:
-- [ ] 19-01: TBD (run /gsd:plan-phase 19 to break down)
+- [ ] 19-01: Backend API for Agent Questions
+- [ ] 19-02: InboxList & MessageCard Components
+- [ ] 19-03: QuestionForm & Input Components
+- [ ] 19-04: Inbox Page Assembly
#### Phase 20: Real-time Subscriptions
diff --git a/.planning/phases/19-agent-inbox/19-01-PLAN.md b/.planning/phases/19-agent-inbox/19-01-PLAN.md
new file mode 100644
index 0000000..88c1719
--- /dev/null
+++ b/.planning/phases/19-agent-inbox/19-01-PLAN.md
@@ -0,0 +1,99 @@
+---
+phase: 19-agent-inbox
+plan: 01
+type: execute
+wave: 1
+depends_on: []
+files_modified: [src/trpc/router.ts]
+autonomous: true
+---
+
+
+Add tRPC procedures to expose structured agent question data to the frontend.
+
+Purpose: The agent inbox UI needs structured question data (options, multiSelect) to render form controls. Questions are stored in-memory on AgentManager via `getPendingQuestions(agentId)`, but no tRPC procedure exposes this. The message table `content` is a plain string and does NOT contain the structured question data. This plan bridges that gap.
+
+Output: Two new tRPC procedures: `getAgentQuestions` and `listWaitingAgents`.
+
+
+
+@~/.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/agent/types.ts
+@src/agent/schema.ts
+
+
+
+
+
+ Task 1: Add getAgentQuestions tRPC procedure
+ src/trpc/router.ts
+
+Add a `getAgentQuestions` query procedure to the appRouter. It should:
+1. Accept `agentIdentifierSchema` input (same as getAgent — name or id)
+2. Resolve the agent via `resolveAgent(ctx, input)`
+3. Call `agentManager.getPendingQuestions(agent.id)`
+4. Return the `PendingQuestions` object (or null if no pending questions)
+
+Place it near the existing `getAgentResult` procedure since it follows the same pattern.
+
+Also add a `listWaitingAgents` query that filters `agentManager.list()` to only agents with `status === 'waiting_for_input'`. This lets the inbox efficiently fetch only agents that have questions without filtering client-side.
+
+Update the JSDoc procedure list comment at the top of appRouter to include both new procedures.
+
+ npx tsc --noEmit (TypeScript compiles without errors)
+
+ - `getAgentQuestions` procedure exists and returns PendingQuestions | null
+ - `listWaitingAgents` procedure exists and returns AgentInfo[] filtered to waiting_for_input
+ - TypeScript compiles clean
+
+
+
+
+ Task 2: Export PendingQuestions and QuestionItem types from shared package
+ packages/shared/src/types.ts
+
+The frontend needs `PendingQuestions` and `QuestionItem` types to properly type the question form props. Export these types from the shared package:
+
+1. In `packages/shared/src/types.ts`, add re-exports for `PendingQuestions` and `QuestionItem` from `../../src/agent/types.js`
+2. If the import path doesn't work with the shared package's rootDir config, define matching interfaces directly in the shared types file (same shapes as in src/agent/types.ts)
+
+The key types needed by the frontend are:
+- `QuestionItem`: `{ id: string; question: string; options?: { label: string; description?: string }[]; multiSelect?: boolean }`
+- `PendingQuestions`: `{ questions: QuestionItem[] }`
+
+ npx tsc --noEmit -p packages/shared/tsconfig.json && npx tsc --noEmit -p packages/web/tsconfig.app.json
+
+ - PendingQuestions and QuestionItem available to import from @codewalk-district/shared
+ - Both frontend and backend packages compile
+
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `npx tsc --noEmit` passes in root
+- [ ] `npm run build` succeeds
+- [ ] New procedures visible in router type
+
+
+
+
+- getAgentQuestions procedure returns structured question data from AgentManager
+- listWaitingAgents returns only agents in waiting_for_input status
+- PendingQuestions/QuestionItem types available in shared package
+- All builds pass
+
+
+
diff --git a/.planning/phases/19-agent-inbox/19-02-PLAN.md b/.planning/phases/19-agent-inbox/19-02-PLAN.md
new file mode 100644
index 0000000..8898385
--- /dev/null
+++ b/.planning/phases/19-agent-inbox/19-02-PLAN.md
@@ -0,0 +1,120 @@
+---
+phase: 19-agent-inbox
+plan: 02
+type: execute
+wave: 1
+depends_on: []
+files_modified: [packages/web/src/components/InboxList.tsx, packages/web/src/components/MessageCard.tsx]
+autonomous: true
+---
+
+
+Build the InboxList and MessageCard components for the agent inbox message list view.
+
+Purpose: These are the entry-point components for the inbox — showing a filterable, sortable list of agent messages. Following the wireframe spec from docs/wireframes/agent-inbox.md.
+
+Output: InboxList and MessageCard components with filter/sort controls and empty state.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+@docs/wireframes/agent-inbox.md
+@packages/web/src/components/InitiativeList.tsx
+@packages/web/src/components/InitiativeCard.tsx
+@packages/web/src/components/StatusBadge.tsx
+@packages/web/src/components/ui/card.tsx
+@packages/web/src/components/ui/badge.tsx
+@packages/web/src/components/ui/button.tsx
+
+
+
+
+
+ Task 1: Create MessageCard component
+ packages/web/src/components/MessageCard.tsx
+
+Create MessageCard following the wireframe spec. Props:
+- `agentName: string` — agent human-readable name
+- `agentStatus: string` — 'waiting_for_input' | 'running' | 'stopped' | etc.
+- `preview: string` — message preview text (truncated)
+- `timestamp: string` — ISO date string for relative time display
+- `requiresResponse: boolean` — determines filled (●) vs empty (○) indicator
+- `isSelected: boolean` — highlighted state
+- `onClick: () => void`
+
+Display:
+- Status indicator: ● (filled circle) when requiresResponse=true, ○ (empty) otherwise
+- Agent name with status text in parentheses (e.g., "gastown (waiting)")
+- Message preview truncated to ~80 chars with ellipsis
+- Relative timestamp using simple helper (e.g., "2 min ago", "1h ago"). Write an inline `formatRelativeTime(isoDate: string): string` helper at the top of the file — do NOT create a separate utils file.
+- Selected state: slightly different background via className toggle
+
+Use shadcn Card as the base, Tailwind for styling. Match the visual density of InitiativeCard.
+
+ npx tsc --noEmit -p packages/web/tsconfig.app.json
+ MessageCard renders with indicator, name, preview, timestamp, and selected state
+
+
+
+ Task 2: Create InboxList component
+ packages/web/src/components/InboxList.tsx
+
+Create InboxList following the wireframe spec. Props:
+- `agents: Array<{ id: string; name: string; status: string; taskId: string; updatedAt: string }>` — agent data
+- `messages: Array<{ id: string; senderId: string | null; content: string; requiresResponse: boolean; status: string; createdAt: string }>` — message data
+- `selectedAgentId: string | null` — currently selected agent
+- `onSelectAgent: (agentId: string) => void` — selection handler
+- `onRefresh: () => void` — refresh handler
+
+Internal state:
+- `filter: 'all' | 'waiting' | 'completed'` — default 'all'
+- `sort: 'newest' | 'oldest'` — default 'newest'
+
+Behavior:
+1. Join agents with their latest message (match message.senderId to agent.id)
+2. Filter: 'waiting' = requiresResponse messages, 'completed' = responded/non-requiring messages, 'all' = everything
+3. Sort by message timestamp (newest or oldest)
+4. Render MessageCard for each result
+5. Show header with count badge: "Agent Inbox (3)" and Refresh button
+6. Filter and sort as simple button groups or select elements (not dropdowns — keep it simple)
+7. Empty state when no messages match filter: "No pending messages" with subtitle text
+
+Follow the pattern from InitiativeList for the list layout structure.
+
+ npx tsc --noEmit -p packages/web/tsconfig.app.json
+
+ - InboxList renders with filter/sort controls
+ - MessageCard instances rendered for each agent+message pair
+ - Empty state shown when no messages
+ - Filter and sort work correctly
+
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes
+- [ ] `npx vite build` in packages/web succeeds
+
+
+
+
+- MessageCard shows indicator, agent name, preview, relative time
+- InboxList filters by waiting/completed/all
+- InboxList sorts by newest/oldest
+- Empty state renders when no messages match
+- All builds pass
+
+
+
diff --git a/.planning/phases/19-agent-inbox/19-03-PLAN.md b/.planning/phases/19-agent-inbox/19-03-PLAN.md
new file mode 100644
index 0000000..92c0bd6
--- /dev/null
+++ b/.planning/phases/19-agent-inbox/19-03-PLAN.md
@@ -0,0 +1,128 @@
+---
+phase: 19-agent-inbox
+plan: 03
+type: execute
+wave: 1
+depends_on: []
+files_modified: [packages/web/src/components/QuestionForm.tsx, packages/web/src/components/OptionGroup.tsx, packages/web/src/components/FreeTextInput.tsx]
+autonomous: true
+---
+
+
+Build the question form components that render multi-question forms with mixed input types.
+
+Purpose: Agents ask structured questions with options (radio/checkbox), multi-select, free-text, and "Other" fields. These components render the question forms inside the message detail view. Following the wireframe spec from docs/wireframes/agent-inbox.md.
+
+Output: QuestionForm, OptionGroup, and FreeTextInput components.
+
+
+
+@~/.claude/get-shit-done/workflows/execute-plan.md
+@~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+@docs/wireframes/agent-inbox.md
+@src/agent/types.ts
+@packages/web/src/components/ui/input.tsx
+@packages/web/src/components/ui/label.tsx
+@packages/web/src/components/ui/textarea.tsx
+@packages/web/src/components/ui/button.tsx
+
+
+
+
+
+ Task 1: Create OptionGroup and FreeTextInput components
+ packages/web/src/components/OptionGroup.tsx, packages/web/src/components/FreeTextInput.tsx
+
+**OptionGroup** — renders radio buttons OR checkboxes for a question's options. Props:
+- `questionId: string` — for form identification
+- `options: Array<{ label: string; description?: string }>` — available choices
+- `multiSelect: boolean` — checkboxes (true) or radio buttons (false)
+- `value: string` — current selection (for radio: single label, for checkbox: comma-separated labels)
+- `onChange: (value: string) => void` — change handler
+- `allowOther?: boolean` — show "Other" free-text option (default true)
+
+Behavior:
+- Radio buttons for single-select (default). Use native HTML radio inputs with Tailwind styling.
+- Checkboxes for multi-select. Use native HTML checkbox inputs with Tailwind styling.
+- Each option shows label and optional description in lighter text
+- "Other" option: text input that auto-selects its radio/checkbox when user types. The "Other" value is whatever the user typed.
+- For multi-select, value is comma-joined selected labels. When "Other" is checked, append the typed text.
+
+**FreeTextInput** — renders when question has NO options (pure free-text). Props:
+- `questionId: string`
+- `value: string`
+- `onChange: (value: string) => void`
+- `multiline?: boolean` — textarea vs single input (default false)
+- `placeholder?: string`
+
+Use shadcn Input for single-line, shadcn Textarea for multiline. Keep it simple.
+
+ npx tsc --noEmit -p packages/web/tsconfig.app.json
+
+ - OptionGroup renders radio or checkbox based on multiSelect prop
+ - "Other" field auto-selects when typed into
+ - FreeTextInput renders Input or Textarea based on multiline prop
+
+
+
+
+ Task 2: Create QuestionForm component
+ packages/web/src/components/QuestionForm.tsx
+
+QuestionForm orchestrates rendering multiple questions with mixed input types. Props:
+- `questions: Array<{ id: string; question: string; options?: Array<{ label: string; description?: string }>; multiSelect?: boolean }>` — structured question data from agent
+- `onSubmit: (answers: Record) => void` — submit handler with questionId→answer map
+- `onCancel: () => void` — cancel handler
+- `isSubmitting?: boolean` — disable form during submission
+
+Internal state:
+- `answers: Record` — maps question ID to answer string
+
+Behavior:
+1. Render each question sequentially with "Q1:", "Q2:", etc. prefix and question text
+2. For each question, determine input type:
+ - If `options` array exists → render OptionGroup (with multiSelect from question)
+ - If no options → render FreeTextInput
+3. Track answers in local state via `onAnswerChange` callbacks
+4. "Send Answers" button: enabled only when ALL questions have non-empty answers
+5. "Cancel" button: always enabled
+6. On submit: call `onSubmit(answers)` with the complete answer map
+7. Button row at bottom: [Cancel] [Send Answers] — right-aligned, matching wireframe
+
+Use shadcn Button for actions.
+
+ npx tsc --noEmit -p packages/web/tsconfig.app.json
+
+ - QuestionForm renders mixed question types from questions array
+ - Submit disabled until all questions answered
+ - onSubmit called with Record mapping questionId to answer
+
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes
+- [ ] `npx vite build` in packages/web succeeds
+
+
+
+
+- OptionGroup handles radio (single-select) and checkbox (multi-select) with "Other" field
+- FreeTextInput handles single-line and multiline inputs
+- QuestionForm renders sequential questions with correct input type per question
+- Submit validates all questions answered
+- All builds pass
+
+
+
diff --git a/.planning/phases/19-agent-inbox/19-04-PLAN.md b/.planning/phases/19-agent-inbox/19-04-PLAN.md
new file mode 100644
index 0000000..1535fe3
--- /dev/null
+++ b/.planning/phases/19-agent-inbox/19-04-PLAN.md
@@ -0,0 +1,139 @@
+---
+phase: 19-agent-inbox
+plan: 04
+type: execute
+wave: 2
+depends_on: ["19-01", "19-02", "19-03"]
+files_modified: [packages/web/src/routes/inbox.tsx]
+autonomous: true
+---
+
+
+Wire the inbox page with tRPC data fetching, message detail panel, and answer submission.
+
+Purpose: Assemble all Phase 19 components into the working inbox route. Connects InboxList + QuestionForm to backend via tRPC, handles the full answer submission flow (submit answers → resume agent), and shows notification messages.
+
+Output: Fully functional Agent Inbox page at /inbox route.
+
+
+
+@~/.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/19-agent-inbox/19-01-SUMMARY.md
+@.planning/phases/19-agent-inbox/19-02-SUMMARY.md
+@.planning/phases/19-agent-inbox/19-03-SUMMARY.md
+
+@docs/wireframes/agent-inbox.md
+@packages/web/src/routes/inbox.tsx
+@packages/web/src/routes/initiatives/$id.tsx
+@packages/web/src/lib/trpc.ts
+@packages/web/src/components/InboxList.tsx
+@packages/web/src/components/QuestionForm.tsx
+@packages/web/src/components/MessageCard.tsx
+
+
+
+
+
+ Task 1: Wire inbox page with data fetching, detail panel, and answer submission
+ packages/web/src/routes/inbox.tsx
+
+Replace the stub inbox page with the full implementation. The page has two sections:
+1. **Left/main area**: InboxList showing agents with messages
+2. **Detail panel**: appears when an agent is selected, showing message detail + question form
+
+**Data fetching:**
+- `trpc.listWaitingAgents.useQuery({})` — get agents in waiting_for_input status
+- `trpc.listMessages.useQuery({})` — get all user-addressed messages
+- When agent selected: `trpc.getAgentQuestions.useQuery({ id: selectedAgentId }, { enabled: !!selectedAgentId })` — get structured question data
+
+**Page state:**
+- `selectedAgentId: string | null` — which agent's detail is shown
+- Track loading/error states for each query
+
+**Message Detail section** (inline in this file, not a separate component — it's page-specific):
+- Header: agent name, relative timestamp, task info (use agent.taskId to show task reference)
+- If agent has pending questions: render QuestionForm with the structured questions
+- If message is notification (requiresResponse=false): show content with "Dismiss" button
+
+**Answer submission flow:**
+1. User fills QuestionForm and clicks "Send Answers"
+2. Call `trpc.resumeAgent.useMutation()` with `{ id: selectedAgentId, answers }`
+3. On success: invalidate listWaitingAgents and listMessages queries, clear selectedAgentId
+4. On error: show error message
+
+**Notification handling:**
+- For messages with `requiresResponse: false` (type='info'), show content text
+- "Dismiss" button: call `trpc.respondToMessage.useMutation()` to mark as responded, then invalidate queries
+
+**Layout:**
+- Use responsive grid similar to initiative detail: `lg:grid-cols-[1fr_400px]`
+- InboxList on left, detail panel on right (or stacked on mobile)
+- Loading states: skeleton or spinner matching existing patterns from initiatives pages
+- Error states: simple error text matching existing patterns
+
+Follow patterns established in `initiatives/$id.tsx` for query management, loading states, and mutation/invalidation flow.
+
+ npx tsc --noEmit -p packages/web/tsconfig.app.json && cd packages/web && npx vite build
+
+ - Inbox page fetches agents and messages via tRPC
+ - Selecting an agent shows detail panel with questions
+ - Answer submission calls resumeAgent and refreshes data
+ - Notification messages can be dismissed
+ - Loading and error states handled
+
+
+
+
+ Task 2: Full build verification and integration check
+ packages/web/src/routes/inbox.tsx
+
+Run full build verification:
+1. `npx tsc --noEmit` in root — all TypeScript checks pass
+2. `npm run build` in root — full monorepo build succeeds
+3. `cd packages/web && npx vite build` — frontend bundle builds
+4. Verify route is registered in routeTree.gen.ts for /inbox
+5. Verify no unused imports or type errors
+
+Fix any issues found during verification.
+
+ npm run build (root) succeeds with zero errors
+
+ - All TypeScript checks pass
+ - Monorepo build succeeds
+ - Frontend bundles without errors
+ - /inbox route properly registered
+
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `npx tsc --noEmit` passes in root
+- [ ] `npm run build` succeeds in root
+- [ ] `npx vite build` succeeds in packages/web
+- [ ] /inbox route registered in routeTree.gen.ts
+- [ ] No TypeScript errors or warnings
+
+
+
+
+- Inbox page shows list of waiting agents with their messages
+- Selecting an agent shows structured question form
+- Answer submission calls resumeAgent and refreshes the list
+- Notification messages display content and can be dismissed
+- Loading and error states work correctly
+- All builds pass
+
+
+