|
1 | | -# Design Review: Claude Code Support |
| 1 | +# Claude Code Support — Execution Plan |
2 | 2 |
|
3 | | -## Summary |
| 3 | +## Goal |
4 | 4 |
|
5 | | -T3 Code is clearly being shaped toward multi-provider support, but the current implementation remains codex-first in both contracts and runtime assumptions. Claude Code support should land as a real provider adapter, not as a UI-only toggle. |
| 5 | +Ship `claudeCode` as a first-class provider in the current `apps/server` + `apps/web` stack, with predictable lifecycle behavior, canonical runtime events, and capability-driven UI gating. |
6 | 6 |
|
7 | | -## What Already Helps |
| 7 | +## Architecture Fit |
8 | 8 |
|
9 | | -- provider service / adapter architecture already exists under `apps/server/src/provider` |
10 | | -- provider session directory and resume binding already exist |
11 | | -- runtime events are normalized through canonical provider runtime ingestion |
12 | | -- the web UI already gestures at unavailable providers in the picker |
| 9 | +This track is intentionally aligned to the current codebase, not legacy `apps/renderer` assumptions. |
13 | 10 |
|
14 | | -These are strong foundations. |
| 11 | +### Server runtime path |
15 | 12 |
|
16 | | -## Where Codex Still Leaks Through |
17 | | - |
18 | | -### Contracts |
19 | | - |
20 | | -`ProviderKind` is still effectively locked to Codex, so any provider abstraction above it is narrower than it appears. |
| 13 | +- `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` |
| 14 | +- `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` |
| 15 | +- `apps/server/src/provider/Layers/ProviderAdapterRegistry.ts` |
| 16 | +- `apps/server/src/provider/Layers/ProviderService.ts` |
| 17 | +- `apps/server/src/provider/Layers/ProviderSessionDirectory.ts` |
| 18 | +- `apps/server/src/provider/Layers/ProviderHealth.ts` |
| 19 | +- `apps/server/src/serverLayers.ts` |
| 20 | +- `apps/server/src/wsServer.ts` |
21 | 21 |
|
22 | | -Areas to widen first: |
| 22 | +### Shared contracts / model path |
23 | 23 |
|
24 | 24 | - `packages/contracts/src/orchestration.ts` |
25 | 25 | - `packages/contracts/src/provider.ts` |
| 26 | +- `packages/contracts/src/providerRuntime.ts` |
26 | 27 | - `packages/contracts/src/model.ts` |
27 | | - |
28 | | -### Runtime protocol assumptions |
29 | | - |
30 | | -Codex-specific semantics are still embedded in: |
31 | | - |
32 | | -- `apps/server/src/codexAppServerManager.ts` |
33 | | -- `apps/server/src/provider/Layers/CodexAdapter.ts` |
34 | | -- collaboration mode / effort settings |
35 | | -- model selection and account handling |
36 | | -- resume semantics and turn lifecycle mapping |
37 | | - |
38 | | -### UI assumptions |
39 | | - |
40 | | -The UI already lists `claudeCode` as unavailable, but provider capabilities are not yet modeled deeply enough for different approval semantics, tool event shapes, or model option behavior. |
41 | | - |
42 | | -## Recommended Direction |
43 | | - |
44 | | -Treat Claude Code support as a canonical provider implementation with a first-class adapter and a capability matrix. |
45 | | - |
46 | | -### Phase 1 — widen contracts |
47 | | - |
48 | | -- expand `ProviderKind` to include `claudeCode` |
49 | | -- add provider capability contracts: |
50 | | - - model switch mode |
51 | | - - approval support |
52 | | - - user input support |
53 | | - - collaboration / planning support |
54 | | - - resume support level |
55 | | - |
56 | | -### Phase 2 — add adapter |
57 | | - |
58 | | -Introduce: |
59 | | - |
60 | | -- `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` |
61 | | -- `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` |
62 | | - |
63 | | -This adapter should be responsible for: |
64 | | - |
65 | | -- session startup |
66 | | -- send turn |
67 | | -- interrupt / stop |
68 | | -- request/approval response mapping |
69 | | -- event normalization into canonical `ProviderRuntimeEvent` |
70 | | - |
71 | | -### Phase 3 — runtime normalization |
72 | | - |
73 | | -Ensure `ProviderRuntimeIngestion` stays provider-agnostic by consuming canonical runtime events only. |
74 | | - |
75 | | -If Claude requires provider-specific preprocessing, keep that inside the adapter layer. |
76 | | - |
77 | | -### Phase 4 — UI enablement |
78 | | - |
79 | | -- enable Claude in the provider picker only after the adapter is usable |
80 | | -- gate unsupported features off capability flags, not hardcoded provider checks |
81 | | - |
82 | | -## Capability Matrix to Add |
83 | | - |
84 | | -Every provider should declare at least: |
85 | | - |
86 | | -- `sessionModelSwitch` |
87 | | -- `supportsApprovals` |
88 | | -- `supportsUserInput` |
89 | | -- `supportsResume` |
90 | | -- `supportsCollaborationMode` |
91 | | -- `supportsImageInputs` |
92 | | -- `supportsReasoningEffort` |
93 | | -- `supportsServiceTier` |
94 | | - |
95 | | -This avoids future branching scattered across `ChatView.tsx`. |
96 | | - |
97 | | -## Reentry Feature Implications |
98 | | - |
99 | | -Claude support should plug into the proposed reentry engine in two ways: |
100 | | - |
101 | | -1. as a runtime signal source through canonical provider events |
102 | | -2. as an optional recap writer backend once the provider is stable |
103 | | - |
104 | | -The recap system should not assume Codex-only event fields or model option semantics. |
105 | | - |
106 | | -## Risks |
107 | | - |
108 | | -- resume behavior may not match Codex thread recovery semantics |
109 | | -- approval and tool event taxonomies may be materially different |
110 | | -- collaboration mode may not have a direct Claude equivalent |
111 | | -- provider-specific prompt tuning for recap generation could leak into server orchestration if not isolated |
112 | | - |
113 | | -## Recommendation |
114 | | - |
115 | | -Do **not** bolt Claude Code onto `CodexAppServerManager`. Instead: |
116 | | - |
117 | | -- keep Codex-specific runtime logic in Codex modules |
118 | | -- add provider capability contracts first |
119 | | -- ship Claude through the existing adapter / registry / service architecture |
120 | | -- keep recap generation behind a separate model broker so runtime provider and recap writer provider can differ |
| 28 | +- `packages/contracts/src/server.ts` |
| 29 | +- `packages/shared/src/model.ts` |
| 30 | + |
| 31 | +### Web path |
| 32 | + |
| 33 | +- `apps/web/src/components/ChatView.tsx` |
| 34 | +- `apps/web/src/composerDraftStore.ts` |
| 35 | +- `apps/web/src/store.ts` |
| 36 | +- `apps/web/src/session-logic.ts` |
| 37 | +- `apps/web/src/appSettings.ts` |
| 38 | +- `apps/web/src/routes/_chat.settings.tsx` |
| 39 | +- `apps/web/src/wsNativeApi.ts` |
| 40 | + |
| 41 | +## Execution Tracks |
| 42 | + |
| 43 | +### 1. Contracts and capability matrix |
| 44 | + |
| 45 | +- Widen `ProviderKind` to include `claudeCode`. |
| 46 | +- Define provider capability contracts in `packages/contracts/src/provider.ts`: |
| 47 | + - `sessionModelSwitch` |
| 48 | + - `supportsApprovals` |
| 49 | + - `supportsUserInput` |
| 50 | + - `supportsResume` |
| 51 | + - `supportsCollaborationMode` |
| 52 | + - `supportsImageInputs` |
| 53 | + - `supportsReasoningEffort` |
| 54 | + - `supportsServiceTier` |
| 55 | + - `supportsConversationRollback` |
| 56 | +- Extend provider model options in `packages/contracts/src/model.ts`: |
| 57 | + - Codex: `reasoningEffort`, `fastMode` |
| 58 | + - Claude Code: `effort` |
| 59 | +- Extend runtime raw-source contracts in `packages/contracts/src/providerRuntime.ts` for Claude-native stream events. |
| 60 | +- Surface provider capabilities through `packages/contracts/src/server.ts` so `server.getConfig` becomes the single source of truth for provider availability + feature gating. |
| 61 | + |
| 62 | +### 2. Server adapter and session lifecycle |
| 63 | + |
| 64 | +- Add a dedicated `ClaudeCodeAdapter` under `apps/server/src/provider`. |
| 65 | +- Keep Codex-specific logic isolated in Codex modules. |
| 66 | +- Use the Claude runtime adapter to own: |
| 67 | + - session startup / resume |
| 68 | + - turn dispatch |
| 69 | + - interrupt / stop |
| 70 | + - canonical event emission |
| 71 | + - capability reporting |
| 72 | +- Preserve `ProviderService` as the cross-provider routing layer. |
| 73 | +- Preserve `ProviderSessionDirectory` as the persisted thread → provider binding / resume binding layer. |
| 74 | +- Register Claude in `ProviderAdapterRegistryLive` and `makeServerProviderLayer()`. |
| 75 | + |
| 76 | +### 3. Health checks and WebSocket/API surface |
| 77 | + |
| 78 | +- Extend `ProviderHealthLive` to probe Claude install/auth status alongside Codex. |
| 79 | +- Keep `server.getConfig` as the main transport surface for provider status + capability data. |
| 80 | +- Ensure `server.configUpdated` pushes continue to carry the latest provider status objects. |
| 81 | +- Do not add a parallel Claude-specific RPC surface unless the orchestration path cannot express a required operation. |
| 82 | + |
| 83 | +### 4. Web provider parity |
| 84 | + |
| 85 | +- Drive provider availability from `server.getConfig().providers`, not hardcoded placeholders. |
| 86 | +- Keep `PROVIDER_OPTIONS` as the UI label list, but compute selectable / unavailable providers from server status. |
| 87 | +- Extend settings to support custom Claude model slugs. |
| 88 | +- Extend the composer model / effort controls so they respect provider capabilities. |
| 89 | +- Gate unsupported features via capabilities instead of provider-name checks: |
| 90 | + - image inputs |
| 91 | + - plan/default interaction mode |
| 92 | + - service tier |
| 93 | + - conversation rollback |
| 94 | +- Keep event rendering provider-agnostic by consuming orchestration projections only. |
| 95 | + |
| 96 | +### 5. Reliability requirements |
| 97 | + |
| 98 | +- Resume / reconnect must rely on persisted provider session bindings, not fragile UI state. |
| 99 | +- Provider restarts must keep behavior deterministic: |
| 100 | + - no silent provider swapping |
| 101 | + - no hidden capability fallback without an explicit runtime warning |
| 102 | +- Partial stream handling must continue to produce stable timeline state if a turn is interrupted mid-stream. |
| 103 | +- Session stop / interrupt flows must settle orchestration thread state instead of leaving it ambiguous. |
| 104 | + |
| 105 | +## Current implementation notes |
| 106 | + |
| 107 | +This implementation track favors shared abstractions over one-off branching: |
| 108 | + |
| 109 | +- provider capabilities are shared through contracts and reused by both server and web |
| 110 | +- provider status and capability data flow through `server.getConfig` |
| 111 | +- UI gating uses capability data instead of hardcoded `provider === "codex"` checks where possible |
| 112 | +- Claude support is added through the existing adapter / registry / service architecture instead of special-casing `wsServer` |
| 113 | + |
| 114 | +## Follow-up work after this track |
| 115 | + |
| 116 | +- Persist a thread-level preferred provider so idle threads do not need model-based provider inference. |
| 117 | +- Add richer Claude permission / elicitation bridging if the adapter surface stabilizes enough to expose it predictably. |
| 118 | +- Add Claude image-input support once the runtime path supports structured non-text turn inputs cleanly. |
| 119 | +- Revisit rollback / checkpoint parity if Claude exposes reversible conversation history primitives. |
| 120 | +- Add targeted integration tests for reconnect, restart, and interrupted partial-stream recovery on Claude sessions. |
0 commit comments