Files
flynn/.planning/phases/01-daemon-decomposition/01-03-PLAN.md
T

9.7 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves
phase plan type wave depends_on files_modified autonomous must_haves
01-daemon-decomposition 03 execute 2
01-01
01-02
src/daemon/index.ts
true
truths artifacts key_links
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
path provides exports min_lines max_lines
src/daemon/index.ts Thin composition root — imports, wiring, lifecycle, DaemonContext
DaemonContext
startDaemon
Lifecycle
createClientFromConfig
anthropicToGitHubModel
createAutoFallbackClient
createModelRouter
100 200
from to via pattern
src/daemon/index.ts src/daemon/models.ts re-export for backward compatibility export.*from.*['"]./models.js['"]
from to via pattern
src/daemon/index.ts src/daemon/memory.ts import initMemory import.*initMemory.*from.*['"]./memory.js['"]
from to via pattern
src/daemon/index.ts src/daemon/tools.ts import initTools import.*initTools.*from.*['"]./tools.js['"]
from to via pattern
src/daemon/index.ts src/daemon/channels.ts import registerChannels import.*registerChannels.*from.*['"]./channels.js['"]
from to via pattern
src/daemon/index.ts src/daemon/agents.ts import initAgents import.*initAgents.*from.*['"]./agents.js['"]
from to via pattern
src/daemon/index.ts src/daemon/routing.ts import createMessageRouter import.*createMessageRouter.*from.*['"]./routing.js['"]
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.

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

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

Task 1: Clean up daemon/index.ts — remove dead imports, extract remaining inline logic src/daemon/index.ts 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:

    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. Run wc -l src/daemon/index.ts — must be ≤ 200 lines. Run pnpm typecheck — no type errors.

  • daemon/index.ts is under 200 lines
  • All imports are clean — no unused imports
  • Section dividers make the file scannable
  • DaemonContext interface is unchanged
Task 2: Final validation — full test suite and line count audit 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 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 pnpm test:run — all tests pass. pnpm typecheck — zero errors. wc -l src/daemon/index.ts ≤ 200.
  • 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
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

<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>
After completion, create `.planning/phases/01-daemon-decomposition/01-03-SUMMARY.md`