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
1515
1616---
1717
18## Current constraints to design around
18## Current constraints to design around (post-Stage 1)
1919
20201. Provider runtime ingestion expects canonical `ProviderRuntimeEvent` shapes, not provider-native payloads.
212. `ProviderService.startSession` currently defaults to `provider: "codex"` unless explicitly provided.
223. `thread.turn.start` has no provider field today, so first-turn provider selection cannot be explicitly requested.
234. `ProviderService` requires adapter `startSession()` to return a `ProviderSession` with `threadId`.
212. Start input now uses typed `providerOptions` and generic `resumeCursor`; top-level provider-specific fields were removed.
223. `resumeCursor` is intentionally opaque outside adapters and must never be synthesized from `providerThreadId`.
234. `ProviderService` still requires adapter `startSession()` to return a `ProviderSession` with `threadId`.
24245. Checkpoint revert currently calls `providerService.rollbackConversation()`, so Claude adapter needs a rollback strategy compatible with current reactor behavior.
25256. 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`:
6161
6262This removes the implicit “Codex unless session already exists” behavior as the only path.
6363
64### 1.3 Provider session start input for Claude runtime knobs
64### 1.3 Provider session start input for Claude runtime knobs (completed)
6565
6666Update `packages/contracts/src/provider.ts`:
6767
681. Extend `ProviderSessionStartInput` with optional Claude-specific fields (for example `claudeBinaryPath`, `permissionMode`, `maxThinkingTokens`).
692. Keep fields optional so current call sites remain valid.
703. Continue using generic `resumeThreadId` + `resumeCursor` as the cross-provider recovery mechanism.
681. Move provider-specific start fields into typed `providerOptions`:
69 - `providerOptions.codex`
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 tests
75### 1.4 Contract tests (completed)
7376
7477Update/add tests in `packages/contracts/src/*.test.ts` for:
7578
76791. New command payload shape.
77802. Provider-aware model resolution behavior.
783. Backward compatibility of existing command/schema decoding.
813. Breaking-change expectations for removed top-level provider fields.
7982
8083---
8184
......@@ -100,9 +103,9 @@ Baseline adapter options to support from day one:
100103
1011041. `cwd`
1021052. `model`
1033. `pathToClaudeCodeExecutable` (from `claudeBinaryPath`)
1044. `permissionMode`
1055. `maxThinkingTokens`
1063. `pathToClaudeCodeExecutable` (from `providerOptions.claudeCode.binaryPath`)
1074. `permissionMode` (from `providerOptions.claudeCode.permissionMode`)
1085. `maxThinkingTokens` (from `providerOptions.claudeCode.maxThinkingTokens`)
1061096. `resume`
1071107. `resumeSessionAt`
1081118. `includePartialMessages`
......@@ -120,7 +123,7 @@ Required capabilities:
1201232. Multi-turn input queue.
1211243. Interrupt support.
1221254. Approval request/response bridge.
1235. Resume support via `resumeThreadId` / `resumeCursor`.
1265. Resume support via opaque `resumeCursor` (parsed inside Claude adapter only).
124127
125128#### 2.2.a Agent SDK details to preserve
126129
......@@ -129,7 +132,7 @@ The adapter should explicitly rely on these SDK capabilities:
1291321. `query()` returns an async iterable message stream and control methods (`interrupt`, `setModel`, `setPermissionMode`, `setMaxThinkingTokens`, account/status helpers).
1301332. Multi-turn input is supported via async-iterable prompt input.
1311343. 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`.
1331365. Hooks can be used for lifecycle signals (`Stop`, `PostToolUse`, etc.) when we need adapter-originated checkpoint/runtime events.
134137
135138#### 2.2.b Effect-native session lifecycle skeleton
......@@ -142,21 +145,23 @@ const acquireSession = (input: ProviderSessionStartInput) =>
142145 Effect.acquireRelease(
143146 Effect.tryPromise({
144147 try: async () => {
148 const claudeOptions = input.providerOptions?.claudeCode;
149 const resumeState = readClaudeResumeState(input.resumeCursor);
145150 const abortController = new AbortController();
146151 const result = query({
147 prompt: makePromptAsyncIterable(input.sessionId),
152 prompt: makePromptAsyncIterable(),
148153 options: {
149154 cwd: input.cwd,
150155 model: input.model,
151 permissionMode: input.permissionMode,
152 maxThinkingTokens: input.maxThinkingTokens,
153 pathToClaudeCodeExecutable: input.claudeBinaryPath,
154 resume: input.resumeThreadId,
155 resumeSessionAt: readResumeCursor(input.resumeCursor),
156 permissionMode: claudeOptions?.permissionMode,
157 maxThinkingTokens: claudeOptions?.maxThinkingTokens,
158 pathToClaudeCodeExecutable: claudeOptions?.binaryPath,
159 resume: resumeState?.threadId,
160 resumeSessionAt: resumeState?.sessionAt,
156161 signal: abortController.signal,
157162 includePartialMessages: true,
158 canUseTool: makeCanUseTool(input.sessionId),
159 hooks: makeClaudeHooks(input.sessionId),
163 canUseTool: makeCanUseTool(),
164 hooks: makeClaudeHooks(),
160165 },
161166 });
162167 return { abortController, result };
......@@ -345,7 +350,8 @@ Define explicit adapter semantics:
345350
3463511. `sessionId`: adapter-owned stable session id.
3473522. `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
350356### 2.5 Rollback/read strategy
351357
......@@ -402,11 +408,12 @@ Update integration tests to ensure:
402408
403409## Phase 4: Orchestration command/reactor updates
404410
405### 4.1 Decider propagation
411### 4.1 Decider propagation (completed)
406412
407413Update `apps/server/src/orchestration/decider.ts`:
408414
4094151. 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
411418### 4.2 ProviderCommandReactor provider selection
412419
......@@ -415,6 +422,7 @@ Update `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts`:
4154221. Prefer provider from turn-start event payload when starting a new session.
4164232. Fallback to existing thread session provider when payload omitted.
4174243. 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
419427Switch behavior policy (explicit in implementation):
420428
......@@ -516,31 +524,26 @@ Confirm both native and canonical provider logs remain useful with multi-adapter
516524
517525## File checklist
518526
519Likely files to touch:
520
5211. `packages/contracts/src/model.ts`
5222. `packages/contracts/src/orchestration.ts`
5233. `packages/contracts/src/provider.ts`
5244. `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` (new)
5255. `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` (new)
5266. `apps/server/src/provider/Layers/ProviderAdapterRegistry.ts`
5277. `apps/server/src/serverLayers.ts`
5288. `apps/server/src/orchestration/decider.ts`
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`.
527Likely remaining files to touch:
528
5291. `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` (new)
5302. `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` (new)
5313. `apps/server/src/provider/Layers/ProviderAdapterRegistry.ts`
5324. `apps/server/src/serverLayers.ts`
5335. `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts`
5346. `apps/web/src/session-logic.ts`
5357. `apps/web/src/components/ChatView.tsx`
5368. Related tests under `apps/server/src/provider/Layers`, `apps/server/src/orchestration/Layers`, `apps/server/integration`, and `apps/web/src`.
533537
534538---
535539
536540## Delivery order
537541
5381. Contracts for provider selection + models.
5392. Claude adapter + unit tests.
5403. Registry/layer wiring.
5414. Reactor updates for provider-aware session start.
5425. Web provider picker + provider-aware models.
5436. Checkpoint/revert compatibility.
5447. End-to-end integration tests and stabilization.
5421. Claude adapter + unit tests on top of the new `providerOptions`/opaque-cursor contracts.
5432. Registry/layer wiring.
5443. Remaining reactor updates for provider-aware session selection/switching invariants.
5454. Web provider picker + provider-aware models.
5465. Checkpoint/revert compatibility.
5476. End-to-end integration tests and stabilization.
545548
546549This order keeps risk isolated and maintains a working orchestrated path at each stage.