Agent OS Exec vs Container VM
When to use a container VM versus Agent OS Exec for running untrusted code.
Agent OS Exec and container VMs both run untrusted code in isolation, but they sit at different points on the weight-versus-flexibility curve. Picking the right one depends on what you need to run.
Agent OS Exec boots a fully virtualized VM for each runtime and runs guest code inside the AgentOS sidecar. There is no Docker daemon, orchestrator, or vendor account: install @rivet-dev/agentos and call JavaScriptRuntime.create() or PythonRuntime.create(). It is built for lightweight, high-fanout code execution like AI tool calls, user scripts, and plugins, where you want granular permissions and a small footprint.
Container VMs (e2b, Daytona, Modal, Cloudflare Containers, and similar) spin up a full OS image with system packages, a writable disk, and the ability to run arbitrary binaries. They are built for heavyweight workloads that need a complete environment: coding agents, long-lived dev sessions, or anything that shells out to native tools.
How isolation works
The biggest difference is what the isolation boundary is made of.
- Agent OS Exec runs guest code in a V8 isolate hosted by the AgentOS sidecar. Every
JavaScriptRuntime.create()is a separate VM with its own virtual filesystem, process table, network policy, and resource accounting. The process-wide sidecar pool is shared by default. Guest code never calls real Node.js builtins, opens a real host socket, or touches the real disk. See Architecture. - Container VMs isolate with OS-level primitives (namespaces, cgroups, or a microVM). The guest runs a real kernel and a real filesystem, so it can do anything a Linux process can, constrained by the container’s configuration.
Agent OS Exec presents normal Linux semantics to the code it runs (a POSIX-like virtual filesystem, processes, pipes, PTYs, sockets) without granting access to the host that backs them.
Comparison
| Dimension | Agent OS Exec | Container VM |
|---|---|---|
| Isolation boundary | Virtualized VM + V8 isolate in a sidecar process | OS container or microVM |
| Setup | npm install @rivet-dev/agentos | Vendor account or Docker host |
| Hardware | Runs on your infrastructure | Often vendor-hosted |
| Filesystem | Virtual, in-memory, per runtime | Full OS filesystem |
| Network | Explicit per-VM allow, deny, or rules | Full, or firewall rules |
| Permissions | Per-scope policy (fs, network, childProcess, process, env, tool) | Coarse, container-level |
| Languages | JavaScript, TypeScript, and Python | Any language the image supports |
| Arbitrary binaries | No (guest binaries run through the VM, not the host) | Yes |
| Crash domain | VM state is isolated; the default sidecar process is shared | One container per VM |
What Agent OS Exec gives you
These capabilities are the reason to reach for Agent OS Exec over a container when the workload fits in a Node-compatible runtime:
- Explicit permissions. Every guest syscall is checked against a per-scope policy before any host resource is touched. The high-level client defaults to allow-all, so pass a restrictive policy for untrusted code. A denied operation fails with
EACCES. See Permissions. - Virtual filesystem. Each runtime gets its own in-memory filesystem. Guest reads and writes never reach the host disk, and two runtimes writing the same path do not collide. See Filesystem.
- Mediated networking. Guest
fetch(),node:http, and raw sockets all flow through the kernel socket table, so you can allow, deny, or rule-match outbound traffic. See Networking. - Process-level isolation. Each runtime is its own VM, and each
execute()orevaluate()call starts a fresh guest process so in-memory state does not leak between executions. See Architecture. - npm compatibility. Real npm packages run unmodified inside the VM, resolved over a faithfully mounted
node_moduleslike a real filesystem. See Module Loading.
When to use each
Use Agent OS Exec when
- You are running JavaScript, TypeScript, or Python (AI tool calls, user scripts, plugins, evaluation loops).
- You want no vendor dependency and to run on your own infrastructure.
- You need granular permissions over the filesystem, network, and child processes.
- You are running many short tasks and want a small per-task footprint.
Use a container VM when
- You need a full OS environment: system packages, arbitrary binaries, or languages beyond a Node-compatible runtime.
- You need a persistent, long-lived environment such as a multi-hour dev session.
- The workload genuinely needs a real kernel and a real disk.
Need a full isolated operating system?
If your workload needs complete VM environments (for example, running coding agents like Claude Code, Codex, or Amp), the VM Agent SDK provides a unified interface for driving agents inside VMs.
A minimal example
Booting an Agent OS Exec runtime takes no infrastructure beyond the installed package. The runtime owns its VM until you dispose it:
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();
}
There is no container to build, no image to pull, and no daemon to keep running.
Performance
Agent OS Exec has no container image to pull or microVM to provision. Its cold start includes VM creation and the first language process; reusing a runtime keeps that VM, its filesystem, and its mounts alive while each execute() call starts a fresh guest process. See Benchmarks for the reproducible public-API benchmark and its measurement boundaries.