Skip to content

Worker topology ​

One long-lived bot process plus three runtime Cloudflare Workers. A separate assets-only Worker serves this documentation.

The bot opens an outbound websocket to Slack (Socket Mode); its port serves the health probe, dashboard and ingress (decision 0003). Durable conversation and run state live in the state Worker's Durable Objects when configured; repository work lives in its execution workspace.

PieceWhat it isWhy it exists
The botOne always-on container with the Slack and model keysThe one thing that must run continuously
State Worker (switchboard-memory)Durable Objects: config overrides, memory, run history and ledger, schedule firingsWhat must survive a bot restart
Resident Worker (switchboard-resident)Per-repository Durable Objects: bare mirror, warm checkout, per-thread worktreesOnboarded repositories stay warm, under their own GitHub credential
Sandbox Worker (switchboard-sandbox)A proxy in front of per-thread containersTool calls that must not touch the bot host

The whole picture ​

A configured ledger writes progress while a run is live; run history keeps its finished record (Runs: live and recorded). The state Worker enforces retention on reads and trims history on writes. Scheduled physical cleanup is paused for the MVP (Known limits). Chat-set overrides persist there when runtimeOverrides.worker names it, otherwise in a file under data/.

How they talk to each other ​

  • Model workspaces receive a revocable run bearer. The trusted Git door exchanges it for repository-scoped GitHub access; the model does not receive an installation token (Execution and trust).
  • A cold sandbox is seeded from the resident's snapshot when the resident cannot take a run: the bot forwards the handle its /status probe carried, and the sandbox Worker restores the checkout and its dependency view from the resident's R2 bucket before the run's first command, so the run starts where a resident's would (execution items 25–26). A repository with no resident, or a resident with no snapshot yet, runs cold as before.
  • The resident's GitHub credential is a second domain: its own App key and its own short-lived tokens, unaffected by rotating the bot's (decision 0009).
  • The state Worker preserves configured run state. The ledger can reclaim a live run after a bot restart; the channel and saved conversation provide later context.
  • A resident redeploy is different: it swaps the isolate under active threads, so it is preflighted and refuses while work is in flight (Operate production).
  • Every hop carries the same trace id. The bot sets traceparent on calls to these Workers only, each adopts it after the bearer checks out, and the public shim strips outside trace context (tracing spec).

Why the deploy order follows from this ​

The state Worker goes first: its migrations must exist before the bot writes, or the bot is a live 500. Resident and sandbox follow because they consume bearers the bot's config names. Each Worker is a separate artifact, so a release rolls only those whose inputs changed, in this order (Ship a release; decision 0015).

Why not serverless ​

The Slack adapter is a Socket Mode daemon, and a run holds a model conversation, a sandbox attach and a card open for minutes; the Workers runtime cannot host that yet, though the seams map onto durable-agent frameworks (decision 0016). Hosting the bot in a Sandbox would re-implement the container deployment with an extra layer.

The runner validates and freezes the selected configuration before upload. After Memory, it publishes those same bytes against the original Bot application before either Resident or Bot. Resident must prove image readiness before Bot can use native execution. A Bot-only deploy also checks the Resident protocol and image registry. Existing bearer provisioning, run continuation, drain and rollback controls remain separate.