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.
| Piece | What it is | Why it exists |
|---|---|---|
| The bot | One always-on container with the Slack and model keys | The one thing that must run continuously |
State Worker (switchboard-memory) | Durable Objects: config overrides, memory, run history and ledger, schedule firings | What must survive a bot restart |
Resident Worker (switchboard-resident) | Per-repository Durable Objects: bare mirror, warm checkout, per-thread worktrees | Onboarded repositories stay warm, under their own GitHub credential |
Sandbox Worker (switchboard-sandbox) | A proxy in front of per-thread containers | Tool 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
/statusprobe 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
traceparenton 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.
Read next
- Onboard a repo — what happens inside the resident Worker.
- Capacity and sizing — why the containers are the size they are.
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.