Meir Dick · November 2026
Cloudflare as an agent runtime
I set out to prove that Cloudflare can run real agents on the user's own account. The agent's machine sleeps when idle, costs nothing while asleep, wakes in seconds, keeps its state, and never holds a credential.
It works. I built it three times, for Amp, OpenClaw and OpenCode, and shipped a Laravel package for Workers AI. The containers were the easy part. The hard part was the control plane around them, and that's what I think Cloudflare should own.
Below: what I built, what it measured, what I learned, and an RFC for Cloudflare's engineers.
≈12 snew Amp thread ready from a project snapshot, against 36–45 s on E2B and Vercel
2.5 sOpenCode workspace restored from a snapshot, same session
0 / 200messages lost across 200 OpenClaw sleep/wake cycles
$7–14a month for an always-reachable OpenClaw assistant
The model: cell, fleet, adapter
Anthropic splits an agent into a harness (the loop), a session (the log) and a sandbox (the machine). Something still has to see every session, start and stop sandboxes, snapshot them and bring them back. Cloudflare gives you an excellent controller for one sandbox. The layer that sees the fleet, every team builds again.
Front doors
Amp orb provider, OpenCode client, chat webhooks, Codex remote
harness vendors
exists
Harness adapter, one per harness
boot, ready, attach, quiesce, export state, resume hook, activity signal
ecosystem, on a standard interface
partial
Fleet plane
session registry, reconcile loop, op journal, quotas, rollout, events, list and inspect
Cloudflare library
missing
Cell: one Durable Object plus one container
lease and fencing, state machine, egress policy, snapshots
Cloudflare
exists
Platform mechanisms
list objects and snapshots, managed snapshot lifecycle, eviction notice, reliable timers, inbound TCP and SSH, stable credential injection
Cloudflare platform
missing
Dashed layers are missing. The adapter layer is partial: Cloudflare's experimental ContainerHarness runs Claude Code and Codex headless, with no interactive attach and no fleet view.
RFC
Fleet primitives for agent sessions on Cloudflare
Summary
A Durable Object plus a container is an excellent cell for one agent session. To run a fleet of sessions behind a real harness (Amp, OpenCode, OpenClaw, Codex, Claude Code), every team rebuilds the same layer: a registry, a reconcile loop, an op journal, a snapshot index, keep-alive, and recovery.
I built that layer three times on Cloudflare, and it was most of the work. This RFC proposes:
- A short list of platform mechanisms only Cloudflare can provide.
- An optional Fleet capability in the Agents SDK.
- A standard harness adapter interface, extending ContainerHarness.
It doesn't ask for a generic lifecycle or for Cloudflare to own sleep policy. That matches your stance of helpers, not base classes.
What already exists, and works well
ctx.container with durable_object scheduling: choosing the image and size at runtime, fast starts, and the Durable Object as controller.
- Filesystem snapshots (beta).
- Interception of outbound requests: the basis for keeping credentials out of the container.
- The Agents SDK
Lifecycle: a durable job queue for one Durable Object, with ownership of its alarm.
- ContainerHarness (experimental): Claude Code and Codex, sessions, operation IDs, event replay, snapshot on idle,
ContainerEgress.
ContainerHarness is very close to the cell-plus-adapter layer. This RFC is about what sits around it.
Problem
A Durable Object controls one container. Nothing controls the fleet, and some of what a fleet needs only the platform can provide. Here is what each of my projects had to build:
| Gap | My workaround | Where |
| No API to list or delete snapshots | A Registry Durable Object that indexes every snapshot handle and project mapping | cf-orbs |
| No list of sessions or containers | The same registry, written to on every state change | cf-orbs, oc-workers |
Alarms are best-effort (a failed setAlarm, a reset Durable Object) | A cron ensure() every 5 minutes that re-arms alarms and restarts dead sessions | oc-workers |
| Spawn and resume outlast a request; a Durable Object can reset mid-wait | An op journal per session: idempotent, with resumable phases | cf-orbs, oc-workers |
| Work inside the container isn't counted as activity; the inactivity timeout maxes out at 6 h | A 60 s alarm that refreshes the timeout, plus a watchdog for maximum awake hours | cf-orbs |
| No warning before eviction | A crash-only design: Litestream WAL streaming to R2, credential write-through, and a resume path | oc-workers |
A missing or expired snapshot only fails later, through monitor() | Racing the readiness probe against the failure, then falling back to the image | cf-orbs |
start() returns before the container is ready; exec doesn't inherit the environment, has no timeout, and cancelling it doesn't kill the process | A wrapper (ContainerPort) and a bootstrap script | cf-orbs |
getTcpPort().fetch refuses https and passes the public Host header through | Rewriting the target to http://container and dropping Host | cf-opencode |
| No inbound TCP or SSH into containers | A shell and SSH over a Worker WebSocket (in progress) | cf-opencode |
| Credential injection is example code; the CA needs root at runtime; the limit is 128 intercepts | Rebuilt egress handlers and Worker gates | cf-opencode, oc-workers |
| No documented API to enable containers on a Durable Object namespace | Found the upload metadata by reading wrangler's source | cf-opencode |
Goals and non-goals
Goals: run N long-lived sessions of a third-party harness, with sleep and wake, resume, visibility and recovery, and no custom infrastructure code. Keep policy (idle timers, image rollout, quotas) in user code.
Non-goals: bigger instances or region pinning, which are already well-known requests; owning the meaning of a harness (what a turn is, what's safe to replay); snapshotting memory.
Proposal
Tier 1: platform mechanisms only Cloudflare can provide
- Enumeration. List the Durable Object instances in a namespace, with container state. List and delete snapshots, from
ctx.container.snapshots and the account API.
- Managed snapshot lifecycle. Refresh a snapshot without restoring it (today a snapshot expires 30 days after its last restore). Fail fast when
start() is given a missing snapshot. Publish snapshot pricing.
- Eviction notice. A hook such as
onContainerStopping({ reason, deadline }), with a grace period long enough to quiesce and snapshot.
- Timers that are always delivered. Guaranteed alarm delivery, or documented semantics plus a periodic tick per object that the platform runs, so a reconcile loop doesn't need cron.
- Liveness and readiness. Activity inside the container counts toward keep-alive.
start() can wait for a readiness probe. exec supports env, timeout, and killing the process on cancel.
- Ingress. TCP and WebSocket passthrough to a container port, with Host preserved and https supported, and an SSH pattern for terminal harnesses.
- Stable credential injection. Promote
ContainerEgress to a declarative platform feature (for each host, which header gets which secret). Trust the CA automatically, raise the 128-rule limit, and let bindings (browser, AI, R2) reach the container through the same path.
Tier 2: Fleet, an optional Agents SDK capability
The pattern is the Kubernetes Agent Sandbox controller, a reconcile loop that keeps each session at its desired state, built on Durable Objects:
interface Fleet {
create(spec: SessionSpec): Promise<SessionRef> // idempotent by id
get(id: string): Promise<SessionStatus>
list(q?: { state?: State; label?: string; cursor?: string }): Promise<Page<SessionStatus>>
setDesired(id: string, d: { state: "awake" | "asleep" | "deleted"; image?: string }): Promise<OpId>
snapshot(id: string): Promise<OpId>
fork(id: string, from?: SnapshotId): Promise<SessionRef>
events(q?: { since?: Cursor }): AsyncIterable<FleetEvent>
}
interface SessionSpec {
id: string; adapter: string; image: string; instance: string
idle: { sleepAfter: Duration; maxAwake?: Duration }
egress: EgressPolicy; labels?: Record<string, string>
}
- Reconcile loop: each session stores its desired and observed state, and a level-triggered loop drives one toward the other. Alarms only speed it up.
- Registry: sharded by tenant or project, written to by each cell on every transition.
- Op journal: every operation has an ID, is idempotent, and has phases that resume after a reset.
- Fencing: an epoch or lease per session, so two containers never write the same state.
- Quotas, rollout (canary or pinned image per session), and events for visibility.
Tier 3: harness adapter interface
Extend containerAgent() and agents/harness/container/runtime to cover interactive harnesses, not only headless prompt submission:
interface HarnessAdapter {
image: ImageRef
boot(ctx): Promise<void> // entrypoint and environment
ready(ctx): Promise<boolean> // readiness probe
attach?(ctx): AttachInfo // URL and protocol for a native client
quiesce(ctx): Promise<void> // flush state before a snapshot
state: { log?: LogExport; paths: string[] } // what has to survive, and where it goes
resume(ctx): Promise<void> // runs after a restore
activity(ctx): Promise<boolean> // whether it's busy
egressHosts: string[] // where credentials get injected
}
The adapters belong to the harness vendors and the community. Cloudflare would publish the interface and a few reference adapters, as it already does for Claude Code and Codex.
Alternatives considered
- Keep everything in user code (today). It works, as these builds show, but every team reinvents it and many get it wrong. Moltworker is the public example: no supervision, backups that expire, and billing 24/7.
- Harness in the Durable Object only (Pi, Codex compiled to WASM). Good for new agents, but most adoption today is existing CLIs and servers that live inside a container.
- A hosted sandbox vendor (E2B, Modal). They ship fleet lifecycle, but give up running in the user's own account, scale to zero next to a Durable Object, and credential injection at the edge, which are Cloudflare's advantages.
Open questions for Cloudflare
- Is enumerating Durable Objects and snapshots on the roadmap, or ruled out by design?
- What are the intended delivery semantics for alarms on objects that control a container?
- Is an eviction notice possible with the current scheduler?
- Would you accept Fleet and the adapter interface as a contribution to
cloudflare/agents, or should they live outside it?
- Will ContainerHarness grow interactive attach, or stay headless?
Ask
A 30-minute call with the Containers and Agents SDK owners. I can walk through the code and the measurement harness, and I'm happy to build the first version of Tier 2 and Tier 3 upstream.