# Claude-CLI Engine — Implementation Plan

## Phases

### Phase 1: Schema, Fields, Database (foundation)
- `schemas/settings.json` — add `"claude-cli"` to `providerConfig.type` enum, change required from `["type", "base_url"]` to `["type"]`, add optional `path`, `permission_mode`, `env` fields
- `settings/fields.js` — add `PROVIDER_PATH`, `PROVIDER_PERMISSION_MODE`, `PROVIDER_ENV`
- `infrastructure/database.js` — `ensureColumn(db, 'sessions', 'claude_session_id', 'TEXT')`
- `package.json` — add `@anthropic-ai/claude-agent-sdk` to `optionalDependencies`

### Phase 2: Provider Resolution
- `llm/provider.js` — pass through `path`, `permissionMode`, `env` fields from provider config in `resolveProviderChain()`. Skip non-openai in `callWithProviderFallback()` instead of throwing. Export new `resolveProviderForSession()`.

### Phase 3: PromptQueue
- `engines/claude-prompt-queue.js` — `PromptQueue` class implementing `AsyncIterable<SDKUserMessage>` with `push()`, `pushSilent()` (shouldQuery:false), `pushMessage()`, `close()`, `abort()`.

### Phase 4: Event Mapper
- `engines/claude-event-mapper.js` — tool name bidirectional mapping (Read↔read_file, Bash↔bash, etc.), MCP prefix stripping (`mcp__veil_tools__X` → `X`), extractors for text/thinking/toolCalls/usage from SDK messages, `toOpenAIToolCalls()` for DB storage.

### Phase 5: In-Process MCP Server
- `engines/claude-tools.js` — `buildMcpServer(ctx)` wraps 14 VeilCli tools (agent_*, task_*, memory_*, todo_*, log_write) using SDK's `tool()` + `createSdkMcpServer()`. JSON Schema → Zod conversion. Runs in-process with direct DB/state access.

### Phase 6: Main Engine
- `engines/claude-engine.js` — `runClaudeSession()` async generator:
  1. Build system prompt via `assembleSystemPrompt()` → pass as `systemPrompt.append`
  2. Build MCP server via `buildMcpServer()`
  3. Create PromptQueue, AbortController
  4. Call SDK `query()` with full options
  5. Store runtime ref for mid-session mutations (`storeRuntime()`)
  6. Iterate `AsyncGenerator<SDKMessage>`:
     - `system/init` → store `claude_session_id` in DB
     - `stream_event/text_delta` → `onStreamChunk()`
     - `assistant` → persist to DB, emit tool.start events (mapped names), drain agent queue
     - `tool_result` → persist to DB, emit tool.end events
     - `result` → accumulate tokens/cost, update session DB
  7. Mode-specific completion (chat.response / task.complete / daemon.tick.complete)
  8. Cleanup: `promptQueue.close()`, `removeRuntime()`
  
  Also: `storeRuntime()`, `getRuntime()`, `removeRuntime()` for mutation proxying.
  
  SDK options built with:
  - `settingSources: []` (disable CLAUDE.md)
  - `disallowedTools: ['TodoWrite', 'TodoRead', 'Agent', 'AskUserQuestion']`
  - `hooks` mapped from settings.hooks (PreToolUse/PostToolUse)
  - `canUseTool` implementing `checkPermission()` logic
  - `maxTurns` from `modeConfig.maxIterations`

### Phase 7: Router Integration
- `core/router.js` — add `resolveEngine()` helper. In each of `runChat()`, `runTask()`, `resumeTask()`, `runSubagent()`, `runDaemonTick()`: check engine type, branch to `runClaudeSession()` or existing `runLoop()`. Add `runClaudeChat()`, `runClaudeTask()` etc. wrapper functions that handle session create/resume, iterate the generator, handle mode-specific results.

### Phase 8: Session Mutation Proxying
- `api/routes/sessions.js` — in PATCH handler: if active claude-cli runtime exists, proxy `model` → `runtime.setModel()`, `model_thinking` → `runtime.setMaxThinkingTokens()`. In POST compact handler: if claude-cli, push `/compact` via `promptQueue.pushMessage()`.

### Phase 9: Testing
Full test matrix across all 4 modes, tool calls, MCP tools, streaming, permissions, cost tracking, session fork/resume, cancellation.

---

## File Summary

**New files (5):**
| File | Lines |
|------|-------|
| `engines/claude-engine.js` | ~350 |
| `engines/claude-tools.js` | ~120 |
| `engines/claude-prompt-queue.js` | ~100 |
| `engines/claude-event-mapper.js` | ~180 |

**Modified files (7):**
| File | Change |
|------|--------|
| `schemas/settings.json` | type enum + fields |
| `settings/fields.js` | 3 constants |
| `infrastructure/database.js` | 1 ensureColumn |
| `llm/provider.js` | pass-through + resolveProviderForSession |
| `core/router.js` | engine branching in 5 functions |
| `api/routes/sessions.js` | mutation proxying |
| `package.json` | optional dep |

## Key Mappings

**Tool names:** Read↔read_file, Write↔write_file, Edit↔edit_file, Bash↔bash, Grep↔grep, Glob↔glob, WebSearch↔web_search, WebFetch↔web_fetch, mcp__veil_tools__X↔X

**Disallowed by default:** TodoWrite, TodoRead, Agent, AskUserQuestion (VeilCli provides its own via MCP)

**Session mutations:** model→setModel(), thinking→setMaxThinkingTokens(), compact→pushMessage('/compact')
