authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-27 00:57:32-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-05 23:00:41-08:00
log931c56b2d0bf873e8923aa51a8e95be929999a5e
tree984d93d725c503890f1e69ac7382fbaa322cf29e
parent484662b2d4bccc1841bb421c9cfd43433b788fd4

revised plan


1 files changed, 49 insertions(+), 46 deletions(-)

.plans/17-claude-code.md+49-46
...@@ -15,12 +15,12 @@ Claude integration must plug into this path instead of reintroducing legacy prov...@@ -15,12 +15,12 @@ Claude integration must plug into this path instead of reintroducing legacy prov
1515
16---16---
1717
18## Current constraints to design around18## Current constraints to design around (post-Stage 1)
1919
201. Provider runtime ingestion expects canonical `ProviderRuntimeEvent` shapes, not provider-native payloads.201. Provider runtime ingestion expects canonical `ProviderRuntimeEvent` shapes, not provider-native payloads.
212. `ProviderService.startSession` currently defaults to `provider: "codex"` unless explicitly provided.212. Start input now uses typed `providerOptions` and generic `resumeCursor`; top-level provider-specific fields were removed.
223. `thread.turn.start` has no provider field today, so first-turn provider selection cannot be explicitly requested.223. `resumeCursor` is intentionally opaque outside adapters and must never be synthesized from `providerThreadId`.
234. `ProviderService` requires adapter `startSession()` to return a `ProviderSession` with `threadId`.234. `ProviderService` still requires adapter `startSession()` to return a `ProviderSession` with `threadId`.
245. Checkpoint revert currently calls `providerService.rollbackConversation()`, so Claude adapter needs a rollback strategy compatible with current reactor behavior.245. Checkpoint revert currently calls `providerService.rollbackConversation()`, so Claude adapter needs a rollback strategy compatible with current reactor behavior.
256. Web currently marks Claude as unavailable (`"Claude Code (soon)"`) and model picker is Codex-only.256. Web currently marks Claude as unavailable (`"Claude Code (soon)"`) and model picker is Codex-only.
2626
...@@ -61,21 +61,24 @@ Update `packages/contracts/src/orchestration.ts`:...@@ -61,21 +61,24 @@ Update `packages/contracts/src/orchestration.ts`:
6161
62This removes the implicit “Codex unless session already exists” behavior as the only path.62This removes the implicit “Codex unless session already exists” behavior as the only path.
6363
64### 1.3 Provider session start input for Claude runtime knobs64### 1.3 Provider session start input for Claude runtime knobs (completed)
6565
66Update `packages/contracts/src/provider.ts`:66Update `packages/contracts/src/provider.ts`:
6767
681. Extend `ProviderSessionStartInput` with optional Claude-specific fields (for example `claudeBinaryPath`, `permissionMode`, `maxThinkingTokens`).681. Move provider-specific start fields into typed `providerOptions`:
692. Keep fields optional so current call sites remain valid.69 - `providerOptions.codex`
703. Continue using generic `resumeThreadId` + `resumeCursor` as the cross-provider recovery mechanism.70 - `providerOptions.claudeCode`
712. Keep `resumeCursor` as the single cross-provider resume input in `ProviderSessionStartInput`.
723. Deprecate/remove `resumeThreadId` from the generic start contract.
734. Treat `resumeCursor` as adapter-owned opaque state.
7174
72### 1.4 Contract tests75### 1.4 Contract tests (completed)
7376
74Update/add tests in `packages/contracts/src/*.test.ts` for:77Update/add tests in `packages/contracts/src/*.test.ts` for:
7578
761. New command payload shape.791. New command payload shape.
772. Provider-aware model resolution behavior.802. Provider-aware model resolution behavior.
783. Backward compatibility of existing command/schema decoding.813. Breaking-change expectations for removed top-level provider fields.
7982
80---83---
8184
...@@ -100,9 +103,9 @@ Baseline adapter options to support from day one:...@@ -100,9 +103,9 @@ Baseline adapter options to support from day one:
100103
1011. `cwd`1041. `cwd`
1022. `model`1052. `model`
1033. `pathToClaudeCodeExecutable` (from `claudeBinaryPath`)1063. `pathToClaudeCodeExecutable` (from `providerOptions.claudeCode.binaryPath`)
1044. `permissionMode`1074. `permissionMode` (from `providerOptions.claudeCode.permissionMode`)
1055. `maxThinkingTokens`1085. `maxThinkingTokens` (from `providerOptions.claudeCode.maxThinkingTokens`)
1066. `resume`1096. `resume`
1077. `resumeSessionAt`1107. `resumeSessionAt`
1088. `includePartialMessages`1118. `includePartialMessages`
...@@ -120,7 +123,7 @@ Required capabilities:...@@ -120,7 +123,7 @@ Required capabilities:
1202. Multi-turn input queue.1232. Multi-turn input queue.
1213. Interrupt support.1243. Interrupt support.
1224. Approval request/response bridge.1254. Approval request/response bridge.
1235. Resume support via `resumeThreadId` / `resumeCursor`.1265. Resume support via opaque `resumeCursor` (parsed inside Claude adapter only).
124127
125#### 2.2.a Agent SDK details to preserve128#### 2.2.a Agent SDK details to preserve
126129
...@@ -129,7 +132,7 @@ The adapter should explicitly rely on these SDK capabilities:...@@ -129,7 +132,7 @@ The adapter should explicitly rely on these SDK capabilities:
1291. `query()` returns an async iterable message stream and control methods (`interrupt`, `setModel`, `setPermissionMode`, `setMaxThinkingTokens`, account/status helpers).1321. `query()` returns an async iterable message stream and control methods (`interrupt`, `setModel`, `setPermissionMode`, `setMaxThinkingTokens`, account/status helpers).
1302. Multi-turn input is supported via async-iterable prompt input.1332. Multi-turn input is supported via async-iterable prompt input.
1313. Tool approval decisions are provided via `canUseTool`.1343. Tool approval decisions are provided via `canUseTool`.
1324. Resume support uses `resume` and optional `resumeSessionAt`.1354. Resume support uses `resume` and optional `resumeSessionAt`, both derived by parsing adapter-owned `resumeCursor`.
1335. Hooks can be used for lifecycle signals (`Stop`, `PostToolUse`, etc.) when we need adapter-originated checkpoint/runtime events.1365. Hooks can be used for lifecycle signals (`Stop`, `PostToolUse`, etc.) when we need adapter-originated checkpoint/runtime events.
134137
135#### 2.2.b Effect-native session lifecycle skeleton138#### 2.2.b Effect-native session lifecycle skeleton
...@@ -142,21 +145,23 @@ const acquireSession = (input: ProviderSessionStartInput) =>...@@ -142,21 +145,23 @@ const acquireSession = (input: ProviderSessionStartInput) =>
142 Effect.acquireRelease(145 Effect.acquireRelease(
143 Effect.tryPromise({146 Effect.tryPromise({
144 try: async () => {147 try: async () => {
148 const claudeOptions = input.providerOptions?.claudeCode;
149 const resumeState = readClaudeResumeState(input.resumeCursor);
145 const abortController = new AbortController();150 const abortController = new AbortController();
146 const result = query({151 const result = query({
147 prompt: makePromptAsyncIterable(input.sessionId),152 prompt: makePromptAsyncIterable(),
148 options: {153 options: {
149 cwd: input.cwd,154 cwd: input.cwd,
150 model: input.model,155 model: input.model,
151 permissionMode: input.permissionMode,156 permissionMode: claudeOptions?.permissionMode,
152 maxThinkingTokens: input.maxThinkingTokens,157 maxThinkingTokens: claudeOptions?.maxThinkingTokens,
153 pathToClaudeCodeExecutable: input.claudeBinaryPath,158 pathToClaudeCodeExecutable: claudeOptions?.binaryPath,
154 resume: input.resumeThreadId,159 resume: resumeState?.threadId,
155 resumeSessionAt: readResumeCursor(input.resumeCursor),160 resumeSessionAt: resumeState?.sessionAt,
156 signal: abortController.signal,161 signal: abortController.signal,
157 includePartialMessages: true,162 includePartialMessages: true,
158 canUseTool: makeCanUseTool(input.sessionId),163 canUseTool: makeCanUseTool(),
159 hooks: makeClaudeHooks(input.sessionId),164 hooks: makeClaudeHooks(),
160 },165 },
161 });166 });
162 return { abortController, result };167 return { abortController, result };
...@@ -345,7 +350,8 @@ Define explicit adapter semantics:...@@ -345,7 +350,8 @@ Define explicit adapter semantics:
345350
3461. `sessionId`: adapter-owned stable session id.3511. `sessionId`: adapter-owned stable session id.
3472. `threadId`: Claude conversation/session identifier returned as `ProviderThreadId`.3522. `threadId`: Claude conversation/session identifier returned as `ProviderThreadId`.
3483. `resumeCursor`: provider-specific cursor (for example message id) needed for precise recovery/rollback.3533. `resumeCursor`: provider-specific cursor (for example thread id + message cursor) needed for precise recovery/rollback.
3544. Orchestration/shared services persist and forward `resumeCursor` unchanged without provider-specific parsing.
349355
350### 2.5 Rollback/read strategy356### 2.5 Rollback/read strategy
351357
...@@ -402,11 +408,12 @@ Update integration tests to ensure:...@@ -402,11 +408,12 @@ Update integration tests to ensure:
402408
403## Phase 4: Orchestration command/reactor updates409## Phase 4: Orchestration command/reactor updates
404410
405### 4.1 Decider propagation411### 4.1 Decider propagation (completed)
406412
407Update `apps/server/src/orchestration/decider.ts`:413Update `apps/server/src/orchestration/decider.ts`:
408414
4091. Carry optional `provider` from `thread.turn.start` command into `thread.turn-start-requested` event payload.4151. Carry optional `provider` from `thread.turn.start` command into `thread.turn-start-requested` event payload.
4162. Keep this behavior provider-agnostic (no provider-specific runtime fields in the event payload).
410417
411### 4.2 ProviderCommandReactor provider selection418### 4.2 ProviderCommandReactor provider selection
412419
...@@ -415,6 +422,7 @@ Update `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts`:...@@ -415,6 +422,7 @@ Update `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts`:
4151. Prefer provider from turn-start event payload when starting a new session.4221. Prefer provider from turn-start event payload when starting a new session.
4162. Fallback to existing thread session provider when payload omitted.4232. Fallback to existing thread session provider when payload omitted.
4173. Fallback to default provider only when neither is present.4243. Fallback to default provider only when neither is present.
4254. On restart/rebind, forward the runtime session's persisted `resumeCursor` as-is (no reconstruction from `providerThreadId`).
418426
419Switch behavior policy (explicit in implementation):427Switch behavior policy (explicit in implementation):
420428
...@@ -516,31 +524,26 @@ Confirm both native and canonical provider logs remain useful with multi-adapter...@@ -516,31 +524,26 @@ Confirm both native and canonical provider logs remain useful with multi-adapter
516524
517## File checklist525## File checklist
518526
519Likely files to touch:527Likely remaining files to touch:
520528
5211. `packages/contracts/src/model.ts`5291. `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` (new)
5222. `packages/contracts/src/orchestration.ts`5302. `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` (new)
5233. `packages/contracts/src/provider.ts`5313. `apps/server/src/provider/Layers/ProviderAdapterRegistry.ts`
5244. `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` (new)5324. `apps/server/src/serverLayers.ts`
5255. `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` (new)5335. `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts`
5266. `apps/server/src/provider/Layers/ProviderAdapterRegistry.ts`5346. `apps/web/src/session-logic.ts`
5277. `apps/server/src/serverLayers.ts`5357. `apps/web/src/components/ChatView.tsx`
5288. `apps/server/src/orchestration/decider.ts`5368. Related tests under `apps/server/src/provider/Layers`, `apps/server/src/orchestration/Layers`, `apps/server/integration`, and `apps/web/src`.
5299. `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts`
53010. `apps/web/src/session-logic.ts`
53111. `apps/web/src/components/ChatView.tsx`
53212. Related tests under `packages/contracts/src`, `apps/server/src/provider/Layers`, `apps/server/src/orchestration/Layers`, `apps/server/integration`, and `apps/web/src`.
533537
534---538---
535539
536## Delivery order540## Delivery order
537541
5381. Contracts for provider selection + models.5421. Claude adapter + unit tests on top of the new `providerOptions`/opaque-cursor contracts.
5392. Claude adapter + unit tests.5432. Registry/layer wiring.
5403. Registry/layer wiring.5443. Remaining reactor updates for provider-aware session selection/switching invariants.
5414. Reactor updates for provider-aware session start.5454. Web provider picker + provider-aware models.
5425. Web provider picker + provider-aware models.5465. Checkpoint/revert compatibility.
5436. Checkpoint/revert compatibility.5476. End-to-end integration tests and stabilization.
5447. End-to-end integration tests and stabilization.
545548
546This order keeps risk isolated and maintains a working orchestrated path at each stage.549This order keeps risk isolated and maintains a working orchestrated path at each stage.