Files
vhaudiquet c1059c23e0 build: the cloud frontend stands alone
The Durable Object, the sandbox daemon, and their deploy assets
leave the rhema workspace for a repository of their own. The DO
was already a deployment artifact (publish = false, worker feature
wasm-only), and rhema-sandbox-server's only consumer was the image
beside it — both are product, not framework. The harness and the
seam stay behind: rhema-cloud-agent and the sandbox family join
the rhema repository's publish list, and this tree consumes them
from crates.io at 0.2.6, the same arrangement the claw keeps its
framework crates under.

The sandboxd image build carries the fix its extraction needed:
the old Dockerfile still staged the claw's workspace (claw and
tools manifests, integrations globs, the vendored crossterm) and
missed rhema-provider-registry's manifest entirely. The manifest
stage is now this workspace's two members, fetched from the
registry.

Not yet buildable: the rhema 0.2.6 batch (rhema-sandbox,
-local, -http, rhema-cloud-agent) must publish first — then one
cargo check generates Cargo.lock and CI goes green.
2026-11-13 12:05:30 +01:00

3.9 KiB
Raw Permalink Blame History

Running the coding agent on Cloudflare

One Durable Object per session: WebSocket chat, streaming model events, bash in a Cloudflare Sandbox container, checkpoints in the DO's SQLite storage. A restart — of the DO, the container, or the worker — resumes the session; a command that died with the container comes back as an "interrupted" tool result, never silently re-run.

Prerequisites

  • A Cloudflare account with Workers Paid: Containers require it, and the bill includes container runtime (see the pricing caveat below).
  • Node (for wrangler and worker-build), Rust with wasm32-unknown-unknown (rustup target add wasm32-unknown-unknown).

Deploy

# from the repository root
npx worker-build --release     # builds crates/rhema-cloudflare-code into build/worker/
npx wrangler deploy -c deploy/cloudflare/wrangler.toml

First deploy creates the CodingAgent and SandboxShim Durable Object classes and the container binding.

Secrets

Two wrangler secrets, never config files, never DO storage:

npx wrangler secret put ANTHROPIC_API_KEY -c deploy/cloudflare/wrangler.toml
npx wrangler secret put SANDBOX_TOKEN     -c deploy/cloudflare/wrangler.toml

ANTHROPIC_API_KEY authenticates the model calls. SANDBOX_TOKEN is any long random string; the agent DO sends it to the sandbox shim on every call, and the shim refuses everything else. Generate one with openssl rand -hex 32.

Driving a session

Every session lives at /sessions/<sessionId>/...:

# Set up the session once: model, approval policy, seed, skills.
curl -X POST https://<worker>/sessions/demo/config \
  -H 'content-type: application/json' \
  -d '{
    "model": "claude-sonnet-4-5",
    "approval": "ask_client",
    "seed_git": "https://github.com/acme/widgets",
    "skills": [{ "name": "deploy",
                 "description": "Triggers on deploy tasks.",
                 "body": "---\ndescription: Triggers on deploy tasks.\n---\n..." }]
  }'

# Chat over a WebSocket: send {"type":"chat","text":"fix the build"},
# receive streaming events; answer approval requests with
# {"type":"approve","id":"...","approve":true}. Stop with {"type":"stop"}.
curl https://<worker>/sessions/demo/session   # the checkpointed record

Approval policies: deny_all (default), allow_list with {"allow_list": ["bash"]}-style tool names, allow_all, and ask_client — requests go over the socket, an unanswered ask denies after 120 s.

Limits and pricing

  • Subrequests: one model fetch plus one or two sandbox calls per step. A step costs 2–3 subrequests against the plan's per-invocation budget (1000 on paid plans), so a 16-step turn spends well under a tenth of it. If turns ever grow past that, the alarm-driven step queue (one invocation per step) is the v2 answer, not limit-raising.
  • CPU: the DO's work is orchestration; the model and the container do the heavy lifting off-thread. Wall-clock, not CPU, is the binding constraint, and workerd allows long-lived WebSocket requests.
  • Container pricing: Containers bill for runtime, not invocations — a container that idles for its inactivity window still costs minutes. The shim keeps one warm for 15 minutes after the last command (INACTIVITY_TIMEOUT_MS); turn that down for cost, up for latency.
  • Workspace persistence: files survive idle sleeps. A full container eviction loses them; the next seeded session re-clones. Treat the sandbox as a checkout, not a store — push early.

What is where

File What it is
wrangler.toml the Worker: DO bindings, SQLite migration, container, vars
entry.mjs the deployable entry: re-exports the classes, routes /sessions/<id>/...
sandbox-shim.mjs the JS DO wrapping ctx.container in the JSON surface the agent DO speaks
../../crates/rhema-cloudflare-code/ the Rust agent: WS protocol, turn loop, checkpoints, fetch transport