---
phase: 01-daemon-decomposition
plan: 03
type: execute
wave: 2
depends_on: ["01-01", "01-02"]
files_modified:
  - src/daemon/index.ts
autonomous: true

must_haves:
  truths:
    - "daemon/index.ts is under 200 lines and contains only imports, wiring calls, lifecycle, and the DaemonContext return"
    - "daemon/index.ts has no business logic — no switch statements, no conditional adapter creation, no tool registration loops"
    - "All 1077+ existing tests pass with zero regressions"
    - "Adding a new model provider requires editing only src/daemon/models.ts"
    - "Adding a new channel adapter requires editing only src/daemon/channels.ts"
    - "The DaemonContext interface is unchanged"
    - "startDaemon() function signature and return type are unchanged"
  artifacts:
    - path: "src/daemon/index.ts"
      provides: "Thin composition root — imports, wiring, lifecycle, DaemonContext"
      exports: ["DaemonContext", "startDaemon", "Lifecycle", "createClientFromConfig", "anthropicToGitHubModel", "createAutoFallbackClient", "createModelRouter"]
      min_lines: 100
      max_lines: 200
  key_links:
    - from: "src/daemon/index.ts"
      to: "src/daemon/models.ts"
      via: "re-export for backward compatibility"
      pattern: "export.*from.*['\"]\\./models\\.js['\"]"
    - from: "src/daemon/index.ts"
      to: "src/daemon/memory.ts"
      via: "import initMemory"
      pattern: "import.*initMemory.*from.*['\"]\\./memory\\.js['\"]"
    - from: "src/daemon/index.ts"
      to: "src/daemon/tools.ts"
      via: "import initTools"
      pattern: "import.*initTools.*from.*['\"]\\./tools\\.js['\"]"
    - from: "src/daemon/index.ts"
      to: "src/daemon/channels.ts"
      via: "import registerChannels"
      pattern: "import.*registerChannels.*from.*['\"]\\./channels\\.js['\"]"
    - from: "src/daemon/index.ts"
      to: "src/daemon/agents.ts"
      via: "import initAgents"
      pattern: "import.*initAgents.*from.*['\"]\\./agents\\.js['\"]"
    - from: "src/daemon/index.ts"
      to: "src/daemon/routing.ts"
      via: "import createMessageRouter"
      pattern: "import.*createMessageRouter.*from.*['\"]\\./routing\\.js['\"]"
---

<objective>
Finalize daemon/index.ts as a thin composition root under 200 lines.

Purpose: After Plans 01 and 02 extracted ~700 lines of business logic into 6 modules, daemon/index.ts should already be significantly shorter. This plan cleans up any remaining inline logic, ensures consistent import structure, removes dead imports, adds section comments, and verifies the final line count meets the <200 line target.

Output: A clean daemon/index.ts that reads as a wiring manifest — you can understand the entire daemon startup by reading one short file.
</objective>

<execution_context>
@/home/will/.config/opencode/get-shit-done/workflows/execute-plan.md
@/home/will/.config/opencode/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md

@.planning/phases/01-daemon-decomposition/01-01-SUMMARY.md
@.planning/phases/01-daemon-decomposition/01-02-SUMMARY.md

@src/daemon/index.ts
@src/daemon/models.ts
@src/daemon/memory.ts
@src/daemon/tools.ts
@src/daemon/channels.ts
@src/daemon/agents.ts
@src/daemon/routing.ts
</context>

<tasks>

<task type="auto">
  <name>Task 1: Clean up daemon/index.ts — remove dead imports, extract remaining inline logic</name>
  <files>src/daemon/index.ts</files>
  <action>
After Plans 01 and 02 completed, daemon/index.ts should be around 300-400 lines. Review and clean up:

1. **Remove dead imports** — Any imports from `../models/`, `../tools/`, `../channels/`, `../automation/`, `../sandbox/`, `../agents/`, `../memory/` that are no longer referenced in daemon/index.ts should be removed. The extracted modules have their own imports now.

2. **Audit remaining inline logic in startDaemon()**. The following should still be in daemon/index.ts (they are pure wiring, not business logic):
   - Data directory creation (2 lines)
   - Session store + manager creation (3 lines)
   - Session pruning timer (10 lines) — this is lifecycle wiring, acceptable
   - Hook engine creation (1 line)
   - initMemory() call (1 line)
   - initTools() call (1 line)
   - MCP manager setup (6 lines)
   - Skills loading (12 lines)
   - initAgents() call (1 line)
   - Audio config (5 lines)
   - Model router creation (1 line)
   - System prompt loading (5 lines)
   - Channel registry creation (1 line)
   - Pairing manager setup (10 lines)
   - Gateway server creation (large config block ~50 lines) — this stays, it's wiring
   - createMessageRouter() call (14 lines)
   - registerChannels() call (1 line)
   - Tier 1 agent tools (15 lines) — these stay (they need deps from multiple init functions)
   - Signal handlers (10 lines)
   - Service startup (channels, gateway, Tailscale, heartbeat) (35 lines)
   - Return DaemonContext

3. **Extract loadSystemPrompt** into its own section or keep it — it's only 15 lines and used once. If daemon/index.ts is still over 200 lines, consider extracting the Tier 1 agent tools block and/or the gateway config block. However, these are wiring code, not business logic — so keeping them is acceptable if under 200 lines.

4. **Organize imports** into clear groups with section comments:
   ```
   // ── External ──
   // ── Config & Types ──
   // ── Daemon Modules ──
   // ── Infrastructure ──
   ```

5. **Add section dividers** in startDaemon() body:
   ```
   // ── Data & Sessions ──
   // ── Core Services ──
   // ── Model & Prompt ──
   // ── Gateway & Channels ──
   // ── Tier 1 Tools ──
   // ── Lifecycle ──
   ```

6. **Verify DaemonContext** interface is unchanged — same fields, same types.

7. **Verify all re-exports** at the bottom of the file:
   ```typescript
   export { createClientFromConfig, anthropicToGitHubModel, createAutoFallbackClient, createModelRouter } from './models.js';
   export { Lifecycle } from './lifecycle.js';
   ```

If the file is still over 200 lines after cleanup, identify what can move:
- The `loadSystemPrompt` function (15 lines) could move to a prompt.ts or stay
- The pairing manager setup (10 lines) could move to channels.ts
- The gateway config block is the largest remaining section — but it's pure wiring

Target: daemon/index.ts ≤ 200 lines.
  </action>
  <verify>
Run `wc -l src/daemon/index.ts` — must be ≤ 200 lines.
Run `pnpm typecheck` — no type errors.
  </verify>
  <done>
- daemon/index.ts is under 200 lines
- All imports are clean — no unused imports
- Section dividers make the file scannable
- DaemonContext interface is unchanged
  </done>
</task>

<task type="auto">
  <name>Task 2: Final validation — full test suite and line count audit</name>
  <files>src/daemon/index.ts, src/daemon/models.ts, src/daemon/memory.ts, src/daemon/tools.ts, src/daemon/channels.ts, src/daemon/agents.ts, src/daemon/routing.ts</files>
  <action>
Run the full validation suite to confirm Phase 1 success criteria:

1. **Run full test suite**: `pnpm test:run` — all 1077+ tests must pass
2. **Run typecheck**: `pnpm typecheck` — zero errors
3. **Run specific daemon tests**: `pnpm test:run src/daemon/` — all daemon tests pass
4. **Line count audit**:
   - `wc -l src/daemon/index.ts` — must be ≤ 200
   - `wc -l src/daemon/models.ts` — should be ~200-250 (model factory + router)
   - `wc -l src/daemon/routing.ts` — should be ~180-220 (message router)
   - `wc -l src/daemon/channels.ts` — should be ~80-100 (adapter registration)
   - `wc -l src/daemon/agents.ts` — should be ~40-60 (agent config + sandbox)
   - `wc -l src/daemon/memory.ts` — should be ~70-100 (memory + vector init)
   - `wc -l src/daemon/tools.ts` — should be ~80-130 (tool registry setup)

5. **Verify module isolation**: Each extracted module imports only from external modules (../models, ../tools, etc.) and from ./lifecycle.js — never from ./index.js (no circular deps).

6. **Verify backward compatibility**: Grep for all imports of `from '../daemon/index.js'` or `from './index.js'` in the test files — all must still resolve.

If any test fails, fix the issue. Common issues:
- Missing re-export in index.ts
- Import path changed
- Type not exported from new module
  </action>
  <verify>
`pnpm test:run` — all tests pass.
`pnpm typecheck` — zero errors.
`wc -l src/daemon/index.ts` ≤ 200.
  </verify>
  <done>
- All 1077+ tests pass
- Zero type errors
- daemon/index.ts ≤ 200 lines
- All 7 daemon module files exist and are correctly sized
- No circular dependencies between daemon modules
- Phase 1 success criteria fully met
  </done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] `pnpm typecheck` passes with zero errors
- [ ] `pnpm test:run` passes all 1077+ tests
- [ ] `pnpm test:run src/daemon/clientFactory.test.ts` passes
- [ ] `pnpm test:run src/daemon/routing.test.ts` passes
- [ ] `pnpm test:run src/daemon/lifecycle.test.ts` passes
- [ ] `wc -l src/daemon/index.ts` shows ≤ 200 lines
- [ ] daemon/index.ts contains NO switch statements
- [ ] daemon/index.ts contains NO conditional adapter creation (`if (config.discord)`)
- [ ] daemon/index.ts contains NO tool registration loops (`for (const tool of ...)`)
- [ ] DaemonContext interface is unchanged from baseline
- [ ] All re-exports present for backward compatibility
</verification>

<success_criteria>
- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- daemon/index.ts is a thin composition root: imports → init calls → wire → lifecycle → return
- Every concern (models, memory, tools, channels, agents, routing) lives in its own module
- DECO-01 through DECO-08 all satisfied
</success_criteria>

<output>
After completion, create `.planning/phases/01-daemon-decomposition/01-03-SUMMARY.md`
</output>
