1# Provider Switching And Context Handoff
2
3Provider switching is a first-class V2 feature. An app thread may contain runs from multiple providers while preserving each provider's native conversation handles and the app's canonical conversation history.
4
5This document describes the provider-switching specialization of the broader [Thread Lineage And Context Transfer](./thread-lineage-and-context-transfer.md) model. Provider switching is a context transfer where the source and target app thread are usually the same thread. Forking, merge-back, and subagents use the same source-point/resolution concepts with different product lifecycles.
6
7## Recommendation
8
9When returning to a provider that was used earlier, default to resuming that provider's previous provider thread and inject a delta summary covering the runs that happened while the provider was inactive.
10
11Create a fresh provider thread with a full app-thread summary only when resuming the prior provider thread fails, settings are incompatible, or delta handoff is likely to produce poor context.
12
13This gives the best default tradeoff:
14
15- preserves native continuity for provider-specific prior work,
16- avoids repeatedly summarizing everything,
17- lets each provider keep its own tool/history affordances,
18- makes cross-provider context explicit and auditable,
19- keeps a clean fallback when old provider context is stale.
20
21## Example
22
23```text
24runs 1-5: Codex, ProviderThread C1
25switch to Claude for run 6
26 -> ContextHandoff H1 covers runs 1-5
27 -> create ProviderThread L1
28 -> run 6 uses L1 with H1
29runs 6-8: Claude, ProviderThread L1
30switch back to Codex for run 9
31 -> ContextHandoff H2 covers runs 6-8
32 -> resume ProviderThread C1
33 -> run 9 uses C1 with H2
34```
35
36ProviderThread C1 is not expected to natively contain Claude's runs. It contains Codex's native conversation plus explicit handoff artifacts that summarize external progress.
37
38## Why Not Always Create A Fresh Provider Thread?
39
40Always creating a fresh provider thread is simpler but loses useful provider-native continuity:
41
42- prior hidden reasoning/context that is only available in the provider thread,
43- provider-side thread metadata,
44- native tool state where available,
45- continuity for provider-specific behavior.
46
47It also forces every switch to depend on full summarization quality. Full summaries are useful fallback artifacts, but they should not be the default when a previous provider thread can be safely resumed.
48
49## Why Not Resume Without Summary?
50
51Because the app thread moved on while the provider was inactive. The resumed provider would not know what another provider did. That creates wrong answers, stale plans, and unsafe file assumptions.
52
53Returning to a provider requires a handoff summary unless no runs happened since that provider last participated.
54
55## Provider Thread Coverage
56
57Provider threads have native coverage and handoff coverage.
58
59```ts
60type ProviderThreadCoverage = {
61 providerThreadId: ProviderThreadId;
62 nativeRunOrdinals: number[];
63 handoffIds: ContextHandoffId[];
64};
65```
66
67For the example above:
68
69```text
70C1 native runs: 1,2,3,4,5,9
71C1 handoffs: H2 covering 6-8
72
73L1 native runs: 6,7,8
74L1 handoffs: H1 covering 1-5
75```
76
77The app thread remains the source of truth for full history.
78
79## Handoff Artifact
80
81A handoff is explicit graph data. In the broader model, `ContextTransfer` records source, target, relationship type, and resolution status. `ContextHandoff` is the materialized portable context artifact used when the transfer cannot be satisfied by native provider continuity.
82
83```ts
84type ContextHandoff = {
85 id: ContextHandoffId;
86 transferId: ContextTransferId;
87 threadId: ThreadId;
88 targetRunId: RunId;
89 fromProviderThreadIds: ProviderThreadId[];
90 toProviderThreadId: ProviderThreadId;
91 coveredRunOrdinals: { from: number; to: number };
92 strategy:
93 | "delta_since_target_last_seen"
94 | "full_thread_summary"
95 | "checkpoint_summary"
96 | "manual_context";
97 summaryText: string;
98 status: "pending" | "ready" | "failed" | "superseded";
99 createdByProvider: ProviderKind | null;
100 createdAt: string;
101 updatedAt: string;
102};
103```
104
105The handoff should be linked to the run that consumes it. If the same summary is regenerated, the old handoff is superseded rather than mutated invisibly.
106
107## Switch Flow
108
109```text
110start run with target provider P
111 -> find current app thread history
112 -> find best ProviderThread for P
113 -> decide handoff strategy
114 -> generate ContextHandoff if needed
115 -> ensure ProviderSession for P
116 -> ensure/resume/create target ProviderThread
117 -> send provider turn with handoff context + user message
118```
119
120The user message remains the actual run input. The handoff context is a separate preamble/system/developer/synthetic-user context depending on provider capability.
121
122## Strategy Selection
123
124Recommended strategy order:
125
1261. No handoff: target provider thread already has current app run coverage.
1272. Delta handoff into existing provider thread: target provider thread can resume and only missed a run range.
1283. Full thread handoff into existing provider thread: target provider can resume, but delta chain is too complex.
1294. Full thread handoff into new provider thread: target provider resume failed, settings are incompatible, or old context is stale.
1305. Unsupported: provider cannot accept handoff context and no safe reconstruction path exists.
131
132## Staleness Policy
133
134The app should be able to decide that returning to an old provider thread is no longer appropriate.
135
136Possible staleness signals:
137
138- too many off-provider runs since last use,
139- too many chained handoffs,
140- target provider model/runtime mode changed incompatibly,
141- provider thread resume failed,
142- prior provider thread was rolled back or forked in a conflicting way,
143- user selected "clean context",
144- handoff summary would exceed provider context policy.
145
146When stale, create a new provider thread with `full_thread_summary`.
147
148## Summarization Source
149
150Summaries can be generated by:
151
152- the provider being left,
153- the provider being entered,
154- a configured summarization provider,
155- a local deterministic summarizer for structured artifacts.
156
157The summary generator is not necessarily the target provider. The handoff records `createdByProvider` so quality and provenance can be inspected later.
158
159## What The Summary Should Contain
160
161The summary should be app-thread canonical, not provider transcript-only.
162
163Include:
164
165- user goals and constraints,
166- decisions made,
167- files changed,
168- commands/tests run,
169- plans/todo state,
170- unresolved approvals/questions,
171- current checkpoint/diff summary,
172- known failures,
173- relevant subagent results.
174
175Do not include:
176
177- irrelevant provider protocol noise,
178- hidden chain-of-thought,
179- stale tool output that is superseded by later runs,
180- large diffs when a file summary is enough.
181
182## Checkpoint Interaction
183
184Provider switching does not change checkpoint ownership. Checkpoints still attach to app runs.
185
186However, handoff generation should reference the latest checkpoint and diff summary so the next provider has a correct workspace-state picture.
187
188```text
189run N completed
190 -> checkpoint N captured
191switch provider for run N+1
192 -> handoff includes summary through checkpoint N
193```
194
195## Rollback Interaction
196
197Rollback invalidates handoffs that cover rolled-back runs.
198
199```text
200rollback to run 5
201 -> runs 6+ marked rolled_back
202 -> handoffs covering 6+ marked superseded
203 -> provider threads whose native/handoff coverage includes 6+ marked divergent or rolled back by capability
204```
205
206If the active provider supports provider rollback, call it. Otherwise, create a new provider thread from the retained app-thread summary when work resumes.
207
208## Forking Interaction
209
210Forking from a mixed-provider app thread should record app-thread lineage and a source point without requiring provider selection at fork time. Provider context is resolved lazily when the first run starts on the fork.
211
212Examples:
213
214- Fork from run 5 on Codex, first fork run uses Codex: prefer Codex native fork if the source refs are strong.
215- Fork from run 5 on Codex, first fork run uses Claude: build portable context lazily at first dispatch.
216- Fork from app checkpoint with no provider-native thread: create target provider thread with checkpoint/full-thread context.
217- Fork from subagent provider thread: use the subagent's provider thread directly if stable, otherwise fall back to portable context.
218
219## Data Model Changes
220
221Provider switching requires:
222
223- `Run.provider`
224- `Run.providerThreadId`
225- `Run.contextHandoffId`
226- `ContextTransfer`
227- `ProviderThread.firstRunOrdinal`
228- `ProviderThread.lastRunOrdinal`
229- `ProviderThread.handoffIds`
230- `ContextHandoff`
231- provider capabilities for handoff support
232
233The app does not need separate conversation threads for provider switches. It needs multiple provider threads attached to the same app thread.