---
phase: 01-daemon-decomposition
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - src/daemon/models.ts
  - src/daemon/memory.ts
  - src/daemon/tools.ts
  - src/daemon/index.ts
autonomous: true

must_haves:
  truths:
    - "createClientFromConfig, anthropicToGitHubModel, createAutoFallbackClient, and createModelRouter are importable from src/daemon/models.ts with identical signatures"
    - "Memory store, vector store, hybrid search, and background indexer initialization works identically when imported from src/daemon/memory.ts"
    - "Tool registration, web search, process tools, browser tools, tool executor, and tool policy setup works identically when imported from src/daemon/tools.ts"
    - "All 1077+ existing tests pass with zero regressions"
    - "clientFactory.test.ts continues to pass without modification"
  artifacts:
    - path: "src/daemon/models.ts"
      provides: "Model client factory, GitHub model mapping, auto-fallback, model router creation"
      exports: ["createClientFromConfig", "anthropicToGitHubModel", "createAutoFallbackClient", "createModelRouter"]
      min_lines: 200
    - path: "src/daemon/memory.ts"
      provides: "Memory store, vector store, hybrid search, and background indexer initialization"
      exports: ["initMemory"]
      min_lines: 60
    - path: "src/daemon/tools.ts"
      provides: "Tool registration, web search, process tools, browser tools, tool executor, tool policy"
      exports: ["initTools"]
      min_lines: 80
  key_links:
    - from: "src/daemon/index.ts"
      to: "src/daemon/models.ts"
      via: "import and call createModelRouter"
      pattern: "import.*from.*['\"]\\./models\\.js['\"]"
    - from: "src/daemon/index.ts"
      to: "src/daemon/memory.ts"
      via: "import and call initMemory"
      pattern: "import.*from.*['\"]\\./memory\\.js['\"]"
    - from: "src/daemon/index.ts"
      to: "src/daemon/tools.ts"
      via: "import and call initTools"
      pattern: "import.*from.*['\"]\\./tools\\.js['\"]"
    - from: "src/daemon/clientFactory.test.ts"
      to: "src/daemon/index.ts"
      via: "re-exports from models.ts"
      pattern: "import.*from.*['\"]\\./index\\.js['\"]"
---

<objective>
Extract model client logic, memory initialization, and tool registration from daemon/index.ts into dedicated modules.

Purpose: These three extractions are the largest code movements (models ~240 lines, memory ~90 lines, tools ~70 lines) and are independent of channel/routing logic. Doing them first reduces daemon/index.ts by ~400 lines.

Output: Three new files (models.ts, memory.ts, tools.ts) with re-exports from daemon/index.ts to preserve the existing public interface.
</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

@src/daemon/index.ts
@src/daemon/clientFactory.test.ts
@src/daemon/lifecycle.ts
</context>

<tasks>

<task type="auto">
  <name>Task 1: Extract model client logic into src/daemon/models.ts</name>
  <files>src/daemon/models.ts, src/daemon/index.ts</files>
  <action>
Create `src/daemon/models.ts` containing these functions moved verbatim from `daemon/index.ts`:

1. **`createClientFromConfig`** (lines 75-146) — the provider switch-case factory
2. **`anthropicToGitHubModel`** (lines 155-184) — Anthropic-to-GitHub model name mapping
3. **`createAutoFallbackClient`** (lines 191-207) — auto fallback for Anthropic tiers
4. **`createModelRouter`** (lines 209-316) — full model router setup with tiers, fallbacks, retry

Move the necessary imports from `daemon/index.ts` to `models.ts`:
- `import type { Config, ModelConfig } from '../config/index.js';`
- `import { AnthropicClient, OpenAIClient, OllamaClient, LlamaCppClient, GeminiClient, BedrockClient, GitHubModelsClient, ModelRouter, DEFAULT_RETRY_CONFIG } from '../models/index.js';`
- `import type { ModelClient, RetryConfig, ModelTier } from '../models/index.js';`

All four functions must be `export`ed with the exact same signatures. JSDoc comments must be preserved.

In `daemon/index.ts`:
- Remove lines 70-316 (the four functions and their imports that are now only used in models.ts)
- Add `import { createClientFromConfig, anthropicToGitHubModel, createAutoFallbackClient, createModelRouter } from './models.js';`
- Add re-exports at the bottom: `export { createClientFromConfig, anthropicToGitHubModel, createAutoFallbackClient, createModelRouter } from './models.js';`

The re-exports are CRITICAL — `clientFactory.test.ts` imports from `./index.js` and must continue to work without modification.

Keep imports in `daemon/index.ts` that are still needed by other code in that file (e.g., `ModelRouter` type for `DaemonContext`).
  </action>
  <verify>
Run `pnpm test:run src/daemon/clientFactory.test.ts` — all tests pass.
Run `pnpm typecheck` — no type errors.
  </verify>
  <done>
- `src/daemon/models.ts` exists with all four exported functions
- `createClientFromConfig`, `anthropicToGitHubModel`, `createAutoFallbackClient`, `createModelRouter` are importable from both `./models.js` and `./index.js`
- clientFactory.test.ts passes without changes
- No type errors
  </done>
</task>

<task type="auto">
  <name>Task 2: Extract memory initialization into src/daemon/memory.ts</name>
  <files>src/daemon/memory.ts, src/daemon/index.ts</files>
  <action>
Create `src/daemon/memory.ts` with a single factory function that encapsulates memory/vector/hybrid-search setup.

Extract from `startDaemon()` lines 549-653 (memory store init, vector store, hybrid search, background indexer, memory tools registration) into a function:

```typescript
export interface MemoryDeps {
  config: Config;
  dataDir: string;
  lifecycle: Lifecycle;
  toolRegistry: ToolRegistry;
}

export interface MemoryResult {
  memoryStore?: MemoryStore;
  hybridSearch?: HybridSearch;
}

export async function initMemory(deps: MemoryDeps): Promise<MemoryResult>
```

The function body should contain the exact logic from lines 549-653:
- Create memoryDir, mkdirSync
- Conditionally create MemoryStore
- If embedding enabled: create embedding provider, VectorStore, HybridSearch, background indexer interval, lifecycle shutdown handlers
- Register memory tools via createMemoryTools
- Return `{ memoryStore, hybridSearch }`

Move only the imports that are exclusively used by memory logic:
- `import { MemoryStore } from '../memory/index.js';`
- `import { VectorStore, HybridSearch, createEmbeddingProvider, chunkText, contentHash } from '../memory/index.js';`
- `import type { EmbeddingProvider as EmbeddingProviderInterface } from '../memory/index.js';`
- `import { createMemoryTools } from '../tools/builtin/index.js';`

In `daemon/index.ts`:
- Replace lines 549-653 with: `const { memoryStore, hybridSearch } = await initMemory({ config, dataDir, lifecycle, toolRegistry });`
- Remove the imports that moved to memory.ts (MemoryStore stays if still referenced in DaemonContext or createMessageRouter types)
- Add `import { initMemory } from './memory.js';`

Note: `MemoryStore` type is used in `createMessageRouter` deps interface. Keep the type import in `daemon/index.ts` if needed, or import it from memory index.
  </action>
  <verify>
Run `pnpm test:run` — all tests pass (memory is integration-tested via daemon tests).
Run `pnpm typecheck` — no type errors.
  </verify>
  <done>
- `src/daemon/memory.ts` exists with `initMemory` exported
- Memory initialization logic removed from `startDaemon()` body
- All tests pass
- No type errors
  </done>
</task>

<task type="auto">
  <name>Task 3: Extract tool registration into src/daemon/tools.ts</name>
  <files>src/daemon/tools.ts, src/daemon/index.ts</files>
  <action>
Create `src/daemon/tools.ts` with a factory function that encapsulates tool registry setup, web search, process tools, browser tools, tool executor, and tool policy.

Extract from `startDaemon()` lines 585-714 (tool registry init, web search, process manager, browser manager, tool executor, tool policy) into:

```typescript
export interface ToolsDeps {
  config: Config;
  lifecycle: Lifecycle;
  hookEngine: HookEngine;
}

export interface ToolsResult {
  toolRegistry: ToolRegistry;
  toolExecutor: ToolExecutor;
  browserManager?: BrowserManager;
}

export function initTools(deps: ToolsDeps): ToolsResult
```

**Important:** The function is NOT async because none of the tool setup is async (process manager, browser manager, tool policy are all synchronous). Only the shutdown handlers are async but those are callbacks registered on lifecycle.

The function body contains the exact logic from lines 585-714:
- Create ToolRegistry, register allBuiltinTools
- Register web search tools (if configured)
- Create ProcessManager, register process tools, lifecycle shutdown
- Create BrowserManager (if enabled), register browser tools, lifecycle shutdown
- Create ToolExecutor with hookEngine
- Create ToolPolicy from config, set on registry, log profile

Move the imports used exclusively by tool setup:
- `import { ToolRegistry, ToolExecutor, ToolPolicy, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager, BrowserManager, createBrowserTools } from '../tools/index.js';`

Keep in `daemon/index.ts` any tool imports still needed (e.g., `ToolRegistry` type for DaemonContext, `createSessionTools`, `createAgentsListTool`, `createMessageSendTool`, `createCronTools`, `createMediaSendTool` for later in startDaemon).

In `daemon/index.ts`:
- Replace lines 585-714 with: `const { toolRegistry, toolExecutor, browserManager } = initTools({ config, lifecycle, hookEngine });`
- Remove the moved imports
- Add `import { initTools } from './tools.js';`

Note: Do NOT move the "Register Tier 1 agent tools" section (lines 975-993) — those depend on sessionManager, agentConfigRegistry, channelRegistry, and cronScheduler which are created later in startDaemon. They stay in daemon/index.ts for now.
  </action>
  <verify>
Run `pnpm test:run` — all tests pass.
Run `pnpm typecheck` — no type errors.
Count lines in daemon/index.ts — should be ~400 lines shorter than baseline (1088).
  </verify>
  <done>
- `src/daemon/tools.ts` exists with `initTools` exported
- Tool registration logic removed from `startDaemon()` body
- Tier 1 agent tools (session, agents list, message send, cron) remain in daemon/index.ts
- All tests pass
- No type errors
- daemon/index.ts is ~650-700 lines (down from 1088)
  </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 (re-export verification)
- [ ] `src/daemon/models.ts` exports: createClientFromConfig, anthropicToGitHubModel, createAutoFallbackClient, createModelRouter
- [ ] `src/daemon/memory.ts` exports: initMemory
- [ ] `src/daemon/tools.ts` exports: initTools
- [ ] daemon/index.ts re-exports model functions for backward compatibility
- [ ] daemon/index.ts is ~650-700 lines (reduced by ~400 lines)
</verification>

<success_criteria>
- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- Each new module file can be read and understood in isolation
- daemon/index.ts is measurably shorter with model/memory/tool logic extracted
</success_criteria>

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