mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Dev Tools

Cloudflare Computer: How a Durable Object Becomes a Filesystem, a Container, and an Agent Runtime

SQLite state in a Durable Object projects into FUSE containers, isolate shells, and ECMAScript modules. One authoritative store, three execution surfaces.

Source: github.com
Cloudflare Computer: How a Durable Object Becomes a Filesystem, a Container, and an Agent Runtime

Cloudflare Computer is a virtual filesystem that lives inside a Durable Object. The Durable Object holds authoritative state in SQLite and exposes three pluggable execution backends: a FUSE-mounted container, an isolate shell, and an ECMAScript module runner. All three share the same filesystem state. The architecture separates where state lives from where code runs, and that boundary matters for security, observability, and multi-backend portability.

The project hit #1 on GitHub Trending for TypeScript with 4,173 stars and 199 forks. Cloudflare released it as a preview, marking APIs unstable and unsuitable for production. The repo includes three working backends and a capnweb RPC channel, making it a rare public example of how to wire Durable Objects, FUSE mounts, and Dynamic Workers into a unified agent execution layer.

Why a Durable Object Holds the Filesystem

The Workspace is the core abstraction. It wraps a Durable Object that stores files, directories, and metadata in SQLite. Every backend reads and writes the same authoritative state. This design avoids the classic agent runtime problem: state scattered across local disks, ephemeral containers, and cloud buckets.

A Workspace can be constructed without any backend. In that mode, you get the filesystem alone. Callers can read, write, and traverse directories over Workers RPC. Backends connect lazily on first use.

The single execution entry point is workspace.runtime.exec(source, { backend }). The backend parameter selects which execution surface to use. The source parameter is either a shell command or an ECMAScript module, depending on the backend.

Three Backends, One State Store

BackendExecution SurfaceState SyncNetwork AccessUse Case
ContainerFUSE mount in sandboxcapnweb RPC to Durable ObjectFull Linux userlandLegacy binaries, system tools, complex builds
Isolate shelljust-bash in Dynamic WorkerWorkers RPC, no second storeCloudflare network onlyShell scripts, CLI orchestration, fast startup
Isolate JavaScriptECMAScript module in Dynamic WorkerWorkspace-backed node:fs/promisesCloudflare network onlyStructured input/output, durable imports, trusted modules

Container Backend

The Container backend projects SQLite state into a sandbox container as a real FUSE mount. A sandbox-side daemon called computerd mounts the state as a filesystem and syncs changes back over a capnweb RPC channel.

The FUSE mount is not a copy. Reads and writes go through the RPC channel to the Durable Object. The container sees a real filesystem, but the authoritative state never leaves SQLite. This gives you full Linux userland, real binaries, and real network access without duplicating state.

The capnweb RPC channel is the security boundary. The sandbox daemon can only call methods exposed by the Durable Object. The Durable Object decides what the container can read, write, and execute. The container cannot bypass the filesystem abstraction to touch SQLite directly.

Isolate Shell Backend

The Isolate shell backend runs just-bash in a Dynamic Worker. It reaches the authoritative Workspace over Workers RPC. There is no second store or sync round trip. The shell reads and writes the Durable Object’s SQLite state directly through the RPC interface.

This design trades Linux compatibility for startup speed and RPC latency. The shell cannot run native binaries, but it starts in milliseconds and avoids the FUSE sync overhead. The RPC call is the only hop between the shell and the state.

The isolate shell is useful for CLI orchestration, shell scripts, and workflows that do not need full Linux. It is faster than spinning up a container and cheaper than keeping a container warm.

Isolate JavaScript Backend

The Isolate JavaScript backend runs an ECMAScript module in a fresh Dynamic Worker. It gets structured input and results, durable relative imports, configured libraries, Workspace-backed node:fs/promises, and trusted ws:git and ws:artifacts modules.

The node:fs/promises implementation is not Node.js. It is a Workspace-backed shim that reads and writes the Durable Object’s SQLite state. The module sees a familiar API, but every filesystem call goes through the same RPC boundary as the isolate shell.

The ws:git and ws:artifacts modules are trusted extensions. They give the module access to Git operations and artifact storage without exposing the full Durable Object API. This is how you build a privilege boundary inside the execution surface.

How the FUSE Mount Syncs State

The Container backend uses a two-layer architecture. The Durable Object exposes a capnweb RPC interface. The sandbox daemon (computerd) implements a FUSE filesystem that calls that interface.

When a process inside the container reads a file, the FUSE driver intercepts the syscall and sends an RPC request to the Durable Object. The Durable Object queries SQLite, returns the file content, and the FUSE driver hands it to the process. Writes follow the same path in reverse.

The FUSE mount is not eventually consistent. Every read and write is a synchronous RPC call. This guarantees that the container always sees the latest state, but it also means that filesystem performance depends on RPC latency.

The capnweb RPC channel is the only way the container can touch the Durable Object. The container cannot open a raw TCP connection to the Durable Object. It cannot bypass the FUSE mount to write SQLite directly. The RPC interface is the security boundary.

State Consistency vs. RPC Latency

The isolate shell skips the FUSE layer and the sync round trip. It calls the Workspace over Workers RPC, which is faster than capnweb RPC to a sandbox. The trade-off is that the shell cannot run native binaries.

The Container backend pays RPC latency on every filesystem operation. The isolate shell pays RPC latency only when it calls the Workspace API. The isolate JavaScript backend pays RPC latency only when it calls node:fs/promises or a trusted module.

This is the core design question: do you need full Linux, or can you live inside a JavaScript runtime? If you need full Linux, you pay the FUSE sync cost. If you can live inside JavaScript, you get faster startup and lower RPC overhead.

Pluggable Execution Surfaces in Practice

A Workspace can register multiple backends under stable IDs. You call workspace.runtime.exec(source, { backend }) and pass the backend ID. The Workspace routes the call to the registered backend.

The backend ID is a string. You can register "container", "isolate-shell", and "isolate-js" in the same Workspace. You can also register custom backends that implement the same interface.

The backend interface is simple. A backend must implement exec(source, options) and return a result. The Workspace does not care how the backend runs the code. It only cares that the backend reads and writes the same SQLite state.

This design lets you mix execution surfaces in the same agent workflow. You can run a shell script to clone a repo, run a JavaScript module to parse the code, and run a container to build a binary. All three backends see the same filesystem.

Security Boundaries and Observability

The Durable Object is the trust root. It holds the authoritative state and exposes the RPC interface. Backends can only call methods that the Durable Object exposes.

The Container backend runs untrusted code inside a sandbox. The sandbox can only touch the filesystem through the FUSE mount. The FUSE mount can only touch the Durable Object through the capnweb RPC channel. The RPC channel enforces the security boundary.

The isolate backends run untrusted code inside a Dynamic Worker. The Worker can only touch the filesystem through the Workspace API. The Workspace API enforces the same security boundary as the capnweb RPC channel.

Observability is a function of the RPC boundary. Every filesystem operation crosses the RPC channel, so you can log, meter, and trace every operation. The Durable Object sees every read, write, and exec call. You can instrument the RPC layer to track latency, error rates, and state mutations.

When to Use a Filesystem Without a Backend

A Workspace can be constructed without a backend. In that mode, you get the filesystem alone. Callers can read, write, and traverse directories over Workers RPC.

This is useful when you want to store agent state in a Durable Object but run execution somewhere else. You can use the Workspace as a durable filesystem for a long-running agent that runs in a Firecracker VM, a Kubernetes pod, or a bare-metal server.

The filesystem-only mode is also useful for testing. You can write tests that manipulate the filesystem without spinning up a container or an isolate. You can verify that the SQLite state is correct without running any code.

Deployment Shape and Failure Modes

Cloudflare Computer runs on Cloudflare Workers. The Durable Object lives in a Cloudflare data center. The Container backend runs in a sandbox that Cloudflare provisions. The isolate backends run in Dynamic Workers that Cloudflare provisions.

The Durable Object is the single point of failure. If the Durable Object crashes, the filesystem state is lost. Cloudflare does not document Durable Object durability guarantees for preview features, so you should assume that state can be lost.

The Container backend depends on sandbox availability. If Cloudflare cannot provision a sandbox, the backend fails. The isolate backends depend on Dynamic Worker availability. If Cloudflare cannot provision a Worker, the backend fails.

The capnweb RPC channel is a network dependency. If the RPC channel fails, the Container backend cannot sync state. The FUSE mount will block until the RPC channel recovers or times out.

The Workers RPC channel is a network dependency. If the RPC channel fails, the isolate backends cannot read or write state. The Workspace API will throw an error.

Code Example: Registering and Using Backends

import { Workspace } from "@cloudflare/computer";

// Construct a Workspace with a Durable Object stub
const workspace = new Workspace(env.COMPUTER);

// Register backends
await workspace.runtime.registerBackend("container", {
  type: "container",
  image: "ubuntu:22.04",
});

await workspace.runtime.registerBackend("isolate-shell", {
  type: "isolate-shell",
});

await workspace.runtime.registerBackend("isolate-js", {
  type: "isolate-javascript",
});

// Write a file to the shared filesystem
await workspace.fs.writeFile("/app/script.sh", "#!/bin/bash\necho 'Hello from container'");
await workspace.fs.writeFile("/app/module.mjs", "export default () => 'Hello from isolate'");

// Execute the shell script in the container
const containerResult = await workspace.runtime.exec("bash /app/script.sh", {
  backend: "container",
});

// Execute the same script in the isolate shell
const shellResult = await workspace.runtime.exec("bash /app/script.sh", {
  backend: "isolate-shell",
});

// Execute the JavaScript module in the isolate
const jsResult = await workspace.runtime.exec("/app/module.mjs", {
  backend: "isolate-js",
});

// All three backends see the same filesystem state
console.log(containerResult.stdout); // "Hello from container"
console.log(shellResult.stdout);     // "Hello from container"
console.log(jsResult);               // "Hello from isolate"

This example shows how to register three backends, write files to the shared filesystem, and execute code in each backend. The filesystem state is the same across all three execution surfaces.

Technical Verdict

Use Cloudflare Computer when you need a durable filesystem for agent workflows that mix shell scripts, JavaScript modules, and Linux binaries. The architecture is clean: one authoritative state store, three pluggable execution surfaces, and a clear RPC boundary for security and observability.

Avoid it when you need production-grade durability guarantees or stable APIs. Cloudflare marks this as preview-only, unsuitable for production, and subject to breaking changes. The Durable Object durability story is unclear, and the capnweb RPC channel is not documented outside this repo.

Use it when you want to experiment with multi-backend agent runtimes. The repo includes working examples of FUSE mounts, isolate shells, and ECMAScript modules, all backed by the same SQLite state. This is a rare public example of how to separate state from execution in an agent runtime.

Avoid it when you need low-latency filesystem operations. Every read and write in the Container backend crosses the capnweb RPC channel. If your workload does thousands of small file operations, the RPC overhead will dominate.

Use it when you want to build privilege boundaries inside agent workflows. The isolate JavaScript backend shows how to expose trusted modules like ws:git and ws:artifacts without giving the module full Durable Object access. This is a useful pattern for sandboxing untrusted agent code.