Provider architecture
The web app communicates with the server via WebSocket using a simple JSON-RPC-style protocol:
- Request/Response:
{ id, method, params }→{ id, result }or{ id, error } - Push events: typed envelopes with
channel,sequence(monotonic per connection), and channel-specificdata
Push channels: server.welcome, server.configUpdated, terminal.event, orchestration.domainEvent. Payloads are schema-validated at the transport boundary (wsTransport.ts). Decode failures produce structured WsDecodeDiagnostic with code, reason, and path info.
Methods mirror the NativeApi interface defined in @t3tools/contracts:
providers.startSession,providers.sendTurn,providers.interruptTurnproviders.respondToRequest,providers.stopSessionshell.openInEditor,server.getConfig
Codex is the only implemented provider. claudeCode is reserved in contracts/UI.
Client transport
wsTransport.ts manages connection state: connecting → open → reconnecting → closed → disposed. Outbound requests are queued while disconnected and flushed on reconnect. Inbound pushes are decoded and validated at the boundary, then cached per channel. Subscribers can opt into replayLatest to receive the last push on subscribe.
Server-side orchestration layers
Provider runtime events flow through queue-based workers:
- ProviderRuntimeIngestion — consumes provider runtime streams, emits orchestration commands
- ProviderCommandReactor — reacts to orchestration intent events, dispatches provider calls
- CheckpointReactor — captures git checkpoints on turn start/complete, publishes runtime receipts
All three use DrainableWorker internally and expose drain() for deterministic test synchronization.