Generated by the
repo-story-timeskill. Companion narrative:THE_STORY_OF_THIS_REPO.md. Source of truth for invariants remainsAGENTS.mdanddocs/design/.
agent-coordinator is the control plane for a hosted coding-agent SDK — a multi-tenant
platform that lets a downstream SaaS spawn autonomous coding agents in isolated cloud sandboxes
and stream their work back to a user in real time.
It is built as a Cloudflare Worker that:
- Authenticates users via Better Auth (cookies,
Authorization: Bearer, andx-api-key) and scopes every operation to a(userId, organizationId)tuple. - Routes each agent session to a per-session
SessionDODurable Object that owns its own SQLite, a WebSocket hub (clients + one sandbox), a FIFO message queue, and an alarm-driven watchdog. - Spawns the data plane on Modal: a sandbox running OpenCode plus an agent bridge that dials back to the DO over a secure WebSocket.
- Persists durable run metadata and tenant data in Postgres (Neon in prod, via the Hyperdrive binding) while keeping ephemeral chat/session state in D1 and DO SQLite.
The problem it solves: running someone else's code-writing agent safely, on your infrastructure, for many tenants at once — with hard isolation, credential least-privilege, durable run history, and live observability.
src/index.ts is the single Hono entry. A request is resolved to a Durable Object by session:
- Real session → D1
session_indexrow → DO ID${organizationId}:${sessionId}. The org prefix is load-bearing: it gives tenant isolation by construction (one org can never name another's DO). - Sandbox-only / handshake → DO ID
sandbox:${sessionId}(smoke tests + the sandbox bridge handshake; auth happens inside the DO by token-hash).
resolveContext() (src/lib/resolve-context.ts) is the single authority that decides the
organizationId. Auth precedence in requireAuth: x-api-key → Bearer token → cookie session.
src/do/session-do.ts (~1500 lines, single actor by design) owns one session end-to-end. It
hibernates when idle and survives hibernation via a private SQLite schema (session,
participants, messages, events, artifacts, sandbox_state, ws_client_mapping),
hibernation-safe WebSockets, and alarms (exec timeout, heartbeat-stale, connecting-timeout,
inactivity → snapshot/cleanup). The FIFO queue is the messages table; processMessageQueue()
is the only dispatcher. Critical events (execution_complete, error, snapshot_ready,
push_complete, push_error) carry an ackId and are re-sent until acknowledged.
packages/modal-infra/ is a vendored Python Modal app exposing api_create_sandbox,
api_sandbox_lifecycle, api_snapshot_sandbox, api_restore_sandbox, api_validate_environment, and api_health, all behind
HMAC auth. packages/sandbox-runtime/ runs inside the sandbox: a supervisor entrypoint, the
bridge that talks the WebSocket protocol back to the DO, and OpenCode integration. The bridge
protocol is duplicated by contract on both sides and must be kept in sync.
- Postgres (authoritative, durable): Better Auth (users/orgs/sessions/api keys) and app
data —
agent_runs,tenant_secret, environment profiles,audit_log. Survives DO reclamation. - D1 (ephemeral routing): backs
session_index(DO routing) and legacy session metadata. - DO SQLite (per-session, hibernation-durable): the live message queue and event log.
ADR docs/decisions/adr/0009-run-store-and-data-boundary.md records the decision that a run == a session
(1:1) for the control plane, with the DO flushing a durable agent_runs row on terminal transitions.
src/index.ts— Hono app: all routes (sessions, runs, usage, events WS, GitHub webhook, secrets, env profiles), middleware, auth wiring, and thescheduledcron export.src/do/session-do.ts— the per-session Durable Object (queue, spawn, bridge event processing, alarms, snapshots).src/do/org-events-do.ts— per-orgOrgEventsDOpoweringGET /api/events/wsfor live cross-tab platform events.src/lib/— the control-plane libraries:resolve-context(org resolution),auth,crypto+secret-repo(per-tenant AES-GCM),github-token-resolver(GitHub-App tokens),modal+modal-auth(data-plane glue),route-auth,require-scope,repo-entitlement,api-key-policy-repo,model-gateway/(LiteLLM + Bifrost adapters),mcp-config(validator).src/contracts/+src/schemas/— Zod contracts for runs, sessions, secrets, usage, environment, and platform events.src/db/— Drizzle schemas: D1 (app-schema, generatedauth-schema) and Postgres (pg/schema.ts,agent-runs-schema.ts).src/cron/repo-image-build.ts— daily repo-image cron (wired, fires0 2 * * *, but gated OFF until its data layer is provisioned).packages/chat/— the consumer chat UI (Void + Vite + React, assistant-ui shell).packages/sdk/,packages/cli/,packages/web/,packages/devtools/,packages/assistant-adapter/,packages/tool-renderers/,packages/deploy/— the SDK and tooling surface a downstream consumer integrates against.packages/modal-infra/+packages/sandbox-runtime/— the vendored Python data plane.
- Runtime: Cloudflare Workers, Durable Objects (SQLite + hibernation), D1, Hyperdrive.
- Language: TypeScript (control plane, SDK, chat), Python (Modal data plane + sandbox runtime).
- Web framework: Hono, migrating to Void (fullstack Vite plugin + CF deploy platform).
- Auth: Better Auth (apiKey, organization plugins) on a Drizzle Postgres adapter.
- Data: Postgres (Neon) via Drizzle; D1 via Drizzle; DO SQLite.
- Data plane: Modal sandboxes running OpenCode; HMAC-authenticated.
- Model routing: LiteLLM gateway (prod at
litellm.omoios.dev), Bifrost adapter. - Testing: Vitest with
@cloudflare/vitest-pool-workers(real Workers isolate + miniflare), Playwright E2E + Vitest browser mode inpackages/chat,pytestfor Python packages. - CI: GitHub Actions (
.github/workflows/ci.yml) with apostgres:18service.
- A consumer SaaS calls the control plane with an API key to create a session/run.
requireAuth+resolveContextresolve(userId, organizationId); the request is routed toSessionDOat${org}:${session}.- The DO spawns a Modal sandbox (
doSpawn), passing a signed run configuration and a hashed auth token; system env vars override user secrets forRESERVED_SYSTEM_KEYS. - The sandbox boots OpenCode + the bridge, which dials back over WSS and presents the bare token once.
- User prompts enter the DO's FIFO queue;
processMessageQueue()dispatches them to the sandbox. - The sandbox streams bridge events (output, tool calls, diffs, completion) back; critical
events are ACKed. Clients receive them over their WebSocket;
OrgEventsDOfans platform-level changes to other tabs. - On terminal transitions the DO flushes a durable
agent_runsrow to Postgres;/api/usageaggregates those rows per org for billing/metering.
Single author — Kevin Hill — across all 231 commits. Ownership is therefore by subsystem convention rather than by person:
- Control plane / routing / auth:
src/index.ts,src/lib/(the most-churned area). - Session lifecycle:
src/do/session-do.ts. - Data plane:
packages/modal-infra/,packages/sandbox-runtime/(vendored from ColeMurray/background-agents; see each package'sDEVIATIONS.md). - Consumer surface:
packages/chat/,packages/sdk/,packages/cli/. - Design source of truth:
docs/design/background-agent-platform/(target) anddocs/design/agent-architecture-review/(as-built gap analysis).
Day-to-day development is heavily agent-orchestrated: the .sisyphus/ directory holds the
planning, prompts, and parallel-subagent harnesses (spawn-goals.sh) that drove the recent
"goal/01–07" parallel work waves.