1# Adding a provider
2
3A provider integration is judged by whether every T3 feature behaves honestly on it, not by
4whether a turn runs. This page lists the decisions and evidence a new driver needs. The
5[provider constraints](./providers.md) and the
6[capability system](../orchestration-v2/provider-capability-system.md) explain why these rules exist.
7
8## Choose the integration shape
9
10- **ACP agents** start as [ACP Registry](../user/providers-acp.md) entries, which follow the ACP
11 spec with no per-agent handling. An agent gets a dedicated driver only when it needs behavior the
12 spec does not cover, and then it is a small flavor over the
13 [shared ACP adapter](../../packages/provider-acp/src/server/adapter.ts), like Grok
14 and Antigravity. Never add agent-id checks to the generic registry adapter.
15- **Other protocols** get a native adapter that implements
16 [`ProviderAdapterV2`](../../packages/provider-core/src/server/ProviderAdapter.ts), like Codex,
17 Claude, Cursor, OpenCode, Pi, and Muse.
18
19Provider-specific behavior stays in the adapter and driver. Orchestration and clients read
20capabilities, never the driver kind.
21
22## Report only what the provider does
23
24- **Capabilities.** Set every flag in `OrchestrationV2ProviderCapabilities` to what the provider
25 really does. Turn off fork, rollback, steering, or subagent support it lacks; orchestration then
26 falls back, for example to portable context handoff for forks. A capability left on that fails
27 at runtime is a bug.
28- **Permission modes.** Offer only modes the provider enforces natively, through
29 `supportedRuntimeModes` in the provider presentation ([Grok](../../packages/provider-grok/src/server/status.ts)
30 and [Pi](../../packages/provider-pi/src/server/status.ts) are examples). Do not imitate a missing
31 mode by answering approvals in T3: T3's check is weaker than the agent's own enforcement. The
32 server runs an unoffered stored mode as Supervised
33 ([`RuntimePolicy.ts`](../../apps/server/src/orchestration-v2/RuntimePolicy.ts)).
34- **Approval and question options.** Pass the provider's own option IDs through unchanged. Every
35 request needs a way to decline that the provider honors.
36- **Interaction modes.** Hide the plan toggle (`showInteractionModeToggle: false`) unless the
37 provider's plan output becomes T3's proposed-plan card.
38
39## Process, account, and setup boundaries
40
41- **Instances.** Session state, catalogs, and credentials belong to a provider instance, not the
42 driver. Remove ambient credentials the instance did not configure, so two instances cannot
43 silently share an account or billing.
44- **Status checks.** Background status and model refreshes must not open a session that can start
45 MCP servers, run hooks, or launch a login. Keep heavier probes behind an explicit refresh.
46- **T3 MCP tools.** Inject the thread's MCP server so agents can use T3's tools, and make a turn
47 survive when that server is unreachable.
48- **Updates.** Run an update only through the installer that provably owns the binary; otherwise
49 leave it manual. See [`providerMaintenance.ts`](../../apps/server/src/provider/providerMaintenance.ts).
50
51## Tests
52
53Prove adapter behavior with replay fixtures: a provider transcript replayed through the real
54orchestrator, adapter, and projections. See the [testing strategy](../orchestration-v2/testing-strategy.md).
55
56- Record transcripts from the real provider with a recorder script in
57 [`apps/server/scripts`](../../apps/server/scripts) (`record-*-replay-fixture.ts`). A new protocol
58 usually needs its own recorder.
59- Cover the shared scenarios under
60 [`testkit/fixtures`](../../apps/server/src/orchestration-v2/testkit/fixtures) that the provider
61 supports: `simple`, `multi_turn`, `queued_turn`, `turn_interrupt`, `message_steering`,
62 `provider_thread_resume`, and the `tool_call_*` approval cases. Add provider-specific fixtures
63 for behavior the shared ones do not reach.
64- Unit tests are for pure logic and for failures a real provider cannot produce on demand. A test
65 that drives the adapter with hand-written frames is a guess about the protocol; live testing
66 regularly finds what those guesses missed.
67- A gated live test against the real binary is welcome, but it does not replace replays, because
68 CI skips it.
69
70## Traps several providers hit
71
72Each of these broke more than one adapter. A replay fixture for each case your provider can
73produce catches them.
74
75- **Settings applied before the provider advertises them.** Agents often list config options after
76 the session opens, in a later update, or only once a model runs (an effort option that exists
77 only for models with effort). An agent can accept a write before then and change nothing. Wait
78 for the option to be advertised before writing it, and treat a stored option the live session
79 does not offer as skipped, not as a failure.
80- **"Default" is a sentinel, not a model.** A default-model selection must switch the session back
81 after a named model ran, including in a resumed session. Never send the sentinel to the
82 provider.
83- **Stop sent before the turn started.** A cancel that reaches the provider before it registered
84 the prompt can be ignored while the turn runs to completion, or can leave a session the provider
85 never saved. Find the provider's own turn-started signal, and test a Stop pressed right after
86 sending.
87- **Work the provider starts on its own.** Background commands, subagents, workflows, and goals can
88 finish or start a turn after T3's turn settled. Offer a continuation through
89 [`ProviderContinuationRequests`](../../packages/provider-core/src/server/continuationRequests.ts)
90 so the parent wakes, and report `hasPendingBackgroundWork` so the session is not released as
91 idle. Dropping it, or killing the session, loses the result.
92- **Subagents outlive the run that launched them.** A child can report after its parent's turn
93 settled, or resume during a later run. Route its updates by the subagent, not by whichever run
94 is currently active.
95- **A failed or stopped turn leaves nothing open.** Settle the turn's tool calls, subagents, and
96 pending approvals and questions. Each terminal path needs its own replay: completion, Stop,
97 provider failure, and process exit.
98- **Usage limits are not generic failures.** Classify quota and rate-limit errors as `usage_limit`
99 with a reset time when the provider gives one, so the thread shows Limited and can resume.
100- **Paths and environment.** Test a symlinked workspace, such as macOS `/tmp`; an agent that
101 compares canonical paths fails every turn there. Drop inherited credentials the instance did not
102 configure. Report unknown sign-in as unknown rather than as signed in.
103
104## Where a driver plugs in
105
106A provider lives in its own `packages/provider-<name>` package, with
107[Pi](../../packages/provider-pi) as the reference. Drivers not moved yet still live in
108[`provider/Drivers`](../../apps/server/src/provider/Drivers).
109
110- **Package exports.** `./settings` holds the instance settings schema, built with
111 `makeProviderSettingsSchema` from contracts. `./client` exports a `ProviderClientDefinition`
112 (label, settings schema, plain-data icon, badge) and must stay browser- and React Native-safe.
113 `./server` exports the `ProviderDriver` and its adapter driver. `./testing` exposes internals
114 the server's replay testkits drive; testkits that need the orchestrator stay in the server.
115 Settings live in `providerInstances`; new providers are off by default.
116- **Package boundaries.** Server code imports only `@t3tools/provider-core/server/*`, contracts,
117 and shared. It reaches the server through `ProviderHost` (paths, settings, background demand,
118 attachments, stored credentials), never through `apps/server`. Tests use `@t3tools/provider-testing`.
119- **Server registration:** the driver's entry in
120 [`builtInDrivers.ts`](../../apps/server/src/provider/builtInDrivers.ts) and the adapter driver's in
121 [`builtInProviderAdapterDrivers.ts`](../../apps/server/src/orchestration-v2/builtInProviderAdapterDrivers.ts).
122 Also its position in the [status order](../../apps/server/src/provider/providerStatusCache.ts), a
123 compatibility policy in [`model-manifest.json`](../../apps/server/src/provider/model-manifest.json)
124 (bump `updatedAt`; see [model manifest](./model-manifest.md)), and its default model in contracts.
125- **Client registration:** the client definition in the web and mobile provider registries, and
126 settings search terms. Clients draw the package icon; do not add a per-driver icon branch.
127- **Docs:** a `docs/user/providers-<name>.md` guide in the product's voice, a row in the
128 [install](../user/install.md#providers) table, and any provider difference that changes the
129 [permission modes](../user/permission-modes.md) page.