Skip to main content
Comparison

Agent OS Exec vs Cloudflare Workers

How Agent OS Exec and Cloudflare Workers differ in isolation model, permissions, networking, and Node.js compatibility.

Agent OS Exec and Cloudflare Workers both run untrusted JavaScript inside V8, but they solve different problems. Workers is a managed, multi-tenant edge platform: you deploy code and Cloudflare runs it for you across its network. Agent OS Exec is a library you embed in your own application to run guest code locally inside a fully virtualized VM that you control. This page focuses on how the two differ in isolation, permissions, networking, and Node.js surface.

At a glance

Agent OS ExecCloudflare Workers
Form factorLibrary you embed (agentos), runs where your app runsManaged edge platform you deploy to
Isolation unitPer runtime: each JavaScriptRuntime.create() is its own VM in the shared sidecar poolPer Worker isolate, scheduled by Cloudflare
Guest runtimeV8 isolate inside a virtualized POSIX kernel (filesystem, processes, sockets, PTYs)V8 isolate with the workerd runtime
PermissionsHost-configured capability policy per VMPlatform-managed; no per-call capability policy
SubprocessesReal node:child_process against kernel-managed processesNot available
FilesystemFull virtualized filesystem per runtimeLimited in-memory node:fs surface, ephemeral
You operate itYes (your process, your machine)No (Cloudflare operates it)

Isolation model

This is the most important difference, and the easiest one to misstate.

Cloudflare Workers isolates code dynamically. Cloudflare’s runtime schedules many Workers into a pool of V8 isolates and can move work between them, with platform-level mitigations (such as I/O-gated clock coarsening) layered on to defend against side-channel attacks across that shared infrastructure.

Agent OS Exec creates a separate kernel-owned VM for every JavaScriptRuntime. VMs do not share filesystems, globals, module state, process tables, sockets, or resource accounting. They use a process-wide shared sidecar pool by default, so sidecar process failure is a wider boundary than VM state isolation. You can provide an explicit sidecar placement when your deployment needs a different failure boundary.

Within a single runtime, every execute() or evaluate() call runs in a fresh guest process, so in-memory state from one execution does not leak into the next.

Process Isolation

How runtimes and runs are isolated, and how to choose granularity.

The practical consequence: with Workers you trust Cloudflare’s platform to keep tenants apart. With Agent OS Exec you get a hard, statically-defined boundary per runtime that you place yourself, which is well suited to running one tenant or one task per runtime and disposing it when finished.

Permissions

Cloudflare Workers does not expose a per-invocation capability policy. What a Worker can reach is governed by its bindings and platform configuration.

Agent OS Exec applies a host-configured capability policy per VM. The high-level client currently defaults scopes to "allow", so applications executing untrusted code should pass an explicit restrictive policy.

import { JavaScriptRuntime } from "@rivet-dev/agentos/javascript";

const runtime = await JavaScriptRuntime.create({
	permissions: {
		fs: "allow",
		network: "deny",
		childProcess: "allow",
		process: "allow",
		env: "allow",
	},
});

try {
	const result = await runtime.evaluate<{
		fileContents: string;
		networkBlocked: boolean;
	}>(`(async () => {
		const { writeFileSync, readFileSync } = await import("node:fs");
		writeFileSync("/workspace/note.txt", "inside the VM");
		let networkBlocked = false;
		try { await fetch("https://example.com"); } catch { networkBlocked = true; }
		return {
			fileContents: readFileSync("/workspace/note.txt", "utf8"),
			networkBlocked,
		};
	})()`);

	if (!result.success) throw new Error(result.error.message);
	console.log(result.value);
} finally {
	await runtime.dispose();
}
An explicitly supplied partial policy denies omitted scopes. See Permissions for a complete execution policy and rule-set syntax.

Networking

Inside the VM, guest fetch() runs through undici in the V8 isolate and then through the kernel’s socket table, gated by the network permission. Guest code can also bind ports inside the VM. The host can observe the process’s readiness output and then send a request with runtime.vm.httpRequest().

From the host side, rt.vm.httpRequest(input) drives an HTTP request into a guest server listening inside the VM and reads the response back. The request never leaves the VM (it connects to the guest’s loopback listener through the kernel socket table), so it works even when guest network egress is denied.

Cloudflare Workers provides outbound fetch() and a Sockets API for outbound TCP/TLS, but a Worker does not listen on a port the way a normal server does; it responds to incoming requests routed by the platform.

import { JavaScriptRuntime } from "@rivet-dev/agentos/javascript";

const serverSource = `
import http from "node:http";
const app = http.createServer((req, res) => {
  res.writeHead(200, { "content-type": "application/json" });
  res.end(JSON.stringify({ ok: true, path: req.url }));
});
app.listen(3000, "127.0.0.1", () => console.log("ready"));
await new Promise(() => {});
`;

const runtime = await JavaScriptRuntime.create({
	permissions: { network: "allow" },
});

let ready!: () => void;
const serverReady = new Promise<void>((resolve) => {
	ready = resolve;
});

try {
	const server = await runtime.spawn(serverSource, {
		onStdout: (chunk) => {
			process.stdout.write(chunk);
			if (chunk.includes("ready")) ready();
		},
	});

	await serverReady;
	const response = await runtime.vm.httpRequest({ port: 3000, path: "/health" });
	console.log(response.status, new TextDecoder().decode(response.body));

	server.kill("SIGTERM");
	await server.wait();
} finally {
	await runtime.dispose();
}

Subprocesses and the POSIX surface

Agent OS Exec presents a virtualized POSIX environment. Guest code can use node:child_process to spawn commands that exist inside the VM (such as sh and the mounted coreutils), and every child is a kernel-managed process, never a real host process. The host can also start a long-running guest program and drive it with rt.spawn().

Cloudflare Workers has no subprocess model. There is no child_process, no process table, and no shell.

Child Processes

Spawn kernel-managed processes from guest code, or drive a long-running guest program from the host.

Node.js compatibility

Both runtimes aim to present Node.js semantics on top of V8, and both implement a large subset of the Node.js standard library. The character of the gaps differs:

  • Agent OS Exec is backed by a real virtualized kernel, so capabilities that need an OS, a full filesystem, real child processes, sockets that listen, and a process table, are first-class. Pure-JS builtins are provided through node-stdlib-browser, and kernel-backed modules (such as fs, net, child_process, dns, http, os) are wired through the bridge to the kernel.
  • Cloudflare Workers provides Node.js compatibility through the nodejs_compat flag on top of workerd. Its filesystem is a limited in-memory surface, there is no subprocess support, and listening servers are replaced by the request/response handler model. In exchange it ships a comprehensive native node:crypto and Web Crypto surface and platform-native logging.
Module support evolves on both sides. Treat the points above as the shape of the difference (kernel-backed POSIX vs managed edge isolate), not a frozen feature matrix. Verify a specific module against the current behavior of whichever runtime you target.

When to choose which

Choose Cloudflare Workers when you want a managed, globally distributed platform to deploy your own trusted code to, with the operations handled for you.

Choose Agent OS Exec when you need to run untrusted or AI-generated code inside your own application with a hard, self-placed isolation boundary, a real virtualized filesystem and process model, and a capability policy you control. One runtime per tenant or per task gives you a clean blast radius you can dispose on demand.

Process Isolation

The isolation model in depth, plus how to pick isolation granularity.