LabPapersPreprint

Sandboxes Without Machines: A V8-Isolate Runtime for Massive Fleets of Resident Agents

Naïve Research7/26/2026Sandbox, RuntimeSandbox researchPDF

Abstract

Agent infrastructure today inherits a premise from serverless computing: every sandbox is a machine — a microVM, container, or gVisor instance — with a kernel boundary, a reserved memory footprint, and a boot time measured in hundreds of milliseconds to seconds. This premise is a poor fit for agents, which are mostly idle (waiting on model inference or external events) and are created, forked, and resumed at high frequency. We present Naïve Sandboxes, a runtime in which a sandbox is a V8 isolate paired with a virtual filesystem and an emulated POSIX shell, with a WebAssembly substitution ladder recovering common developer toolchains in-isolate, and idle agents hibernated to a content-addressed state reference of kilobytes. Across four benchmark iterations on real server hardware (AWS m7i.8xlarge, 32 vCPU / 124 GB), the runtime achieves 2.3 ms create-to-first-exec, ~1 ms warm resume, 1.55 ms copy-on-write forks, and 1.2 MB of RAM per resident agent, and holds 2,000 concurrent agents under heartbeat load at a measured 37.5 ms p99 exec latency. Because a resident agent is memory rather than a machine allocation, an idle agent costs storage rather than reserved RAM. These figures are one to three orders of magnitude beyond published numbers for microVM- and container-based sandboxes, and they follow directly from removing the machine, not from tuning one.

1. Introduction

Sandboxes for AI agents are converging on a shared architecture: a hardware-enforced isolation boundary per agent. E2B runs Firecracker microVMs, Modal runs gVisor containers, Morph and Vercel run microVMs, Cloudflare runs containers. The assumption is that untrusted agent code needs a kernel of its own. The consequences are structural: cold creation costs 90 ms–3 s, each sandbox reserves hundreds of megabytes whether or not it is doing anything, and an “idle” agent is a machine you keep paying for.

Agents violate the workload assumptions behind that design. An agent spends most of its wall-clock life waiting — on model inference, on humans, on cron ticks and webhooks. Its useful state is small: a working directory, environment, session variables, a loop position. And agent orchestration wants machine-like operations to be cheap enough to use casually: fork a live agent per candidate strategy, hibernate a thousand of them overnight, wake one in the time it takes to parse the request.

We asked what happens if the machine is removed entirely. In Naïve Sandboxes, a sandbox is a V8 isolate: the filesystem is virtual (an in-memory, content-addressed VFS persisted to blob storage), the terminal is an emulated shell running inside the isolate (just-bash, with isomorphic-git for version control), and there is no container, no microVM, and no guest kernel. State is first-class: hibernate() serializes an agent to a StateRef of kilobytes; resume() reconstructs it; fork() produces copy-on-write children that share blobs by hash. Toolchains that a bare isolate cannot run natively are recovered by a WebAssembly substitution ladder (§2.5); commands that genuinely need a native toolchain (compilers, browsers, databases) are routed to a metered burst sidecar rather than dragging a full Linux userland into every agent’s footprint.

This paper reports the design and the measured results of four benchmark iterations (v1–v4) that took the runtime from a promising prototype to meeting its north-star latency and density targets on real hardware. The cost target is not among them: what we have is a model, and a model is not a result, so the COGS row is absent from the table below rather than filled in with one.

2. Architecture

The sandbox is fully virtualized: every layer an agent touches — filesystem, shell, toolchain, network policy — is software running inside (or beside) a single V8 isolate. There is no guest kernel anywhere in the stack. Figure 1 contrasts the two models.

Machine per agent (the field)Isolate per agent (Naïve)
agent processagent loop (JS/WASM)
Linux userland (GBs of image)emulated shell + WASM toolchains
guest kernelcontent-addressed virtual FS
microVM / container boundaryV8 isolate boundary (isolated-vm)
reserved RAM: 256–512 MBresident RAM: 1.2 MB
Figure 1. Machine-per-agent vs. isolate-per-agent. Every layer of the Naïve stack is virtualized software; no guest kernel exists.

2.1. One isolate per sandbox

Each sandbox is a V8 isolate created by isolated-vm, giving per-sandbox heap limits, real per-isolate CPU accounting, and a security boundary at the JavaScript engine level. A fresh isolate’s heap is ~653 KB; a resident agent under heartbeat load stabilizes at ~1.2 MB. Because isolate creation is ~2 ms of CPU rather than an OS boot, creation latency is effectively hardware-independent.

2.2. Virtual filesystem and emulated shell

The filesystem is a content-addressed virtual FS: files are hashed blobs, directories are manifests, and persistence is a write of new blobs plus a new manifest hash. The shell is emulated inside the isolate — the coreutils surface agents actually use (file IO, grep/sed/awk, git via isomorphic-git, Python, HTTP) runs natively in the resident tier. A shell-trace coverage gate over a synthesized command corpus tracks which workloads run natively and which are substitutable. Those coverage shares stay internal until the gate is re-run against real agent traces; whatever the ladder cannot cover is routed to the burst tier.

2.3. Hibernation, resume, fork

hibernate() serializes session state and the VFS manifest into a StateRef — kilobytes, not a memory image. Warm resume (in-memory fast path) measures ~1 ms at p50; cold resume rebuilds from the blob store and scales with state size (p95 72.5 ms at 10 MB, 66.1 ms at 50 MB). fork() is a copy-on-write clone — children share all blobs by hash — and measures 1.55 ms at p50. Figure 2 shows the lifecycle.

hot isolate
1.2 MB RAM, live
StateRef
KBs · manifest hash + blobs— hibernate() resume() ~1 ms
child A / child B (CoW)
share blobs by hashfork() 1.55 ms
Figure 2. State is first-class — hibernate to a kilobyte-scale ref, resume in ~1 ms, fork copy-on-write children. Asleep, an agent costs storage only.

2.4. Burst tier

Commands classified as heavy (native compilers, long-running services, browsers) raise BurstRequiredError or are routed to a metered sidecar with real vCPU accounting. The resident loop stays at kilobyte-scale cost; the burst tier is paid for only for the seconds a compiler actually runs.

2.5. The WebAssembly substitution ladder

The gap between an emulated shell and a real developer environment is closed without a kernel by compiling the missing tools to WebAssembly and running them inside the same isolate boundary. Every command an agent executes is classified into one of four classes: native (runs directly on just-bash / isomorphic-git in the resident tier), substitutable (a bare isolate cannot run it, but a ladder rung recovers it in-place), burst (needs real external compute), or fail-other (unknown binary, no mapped mitigation).

The substitution ladder has three main rungs:

native → resident tier
just-bash · coreutils · isomorphic-git · HTTP proxyops commands
substitutable → WASM ladder
tsc · prettier · esbuild-wasm · sql.js · Pyodide · lockfile-addressed dep layers · node child isolatescoding commands
burst → metered sidecar
cargo/gcc · docker · browsers · billed per vCPU-sthe remainder
Figure 3. The command classifier and the WASM substitution ladder. Measured coverage shares are held internal until the gate is re-run against real agent traces.

This ladder is what makes the coverage in §2.2 possible: on the trace gate it moves a large share of coding-agent commands from not-covered to substitutable, and so off the burst tier, while keeping the machine out of the sandbox. The measured shares stay internal until the gate runs on real traces.

3. Methodology

Every number in this report obeys the repository’s benchmark methodology: latencies are distributions (p50/p95/p99 with sample size, date, and a machine fingerprint including the isolate backend); warm and cold paths are separate metrics, never blended; measured, published, modeled, and synthetic sources are flagged and never averaged together; cost figures travel with their workload and billing model; density figures name their host and the SLO they were held under. All headline figures below are measured on AWS m7i.8xlarge (Intel Xeon 8488C, 32 vCPU / 124 GB, Linux, Node 22.23) on the isolated-vm backend with true fleets — the density runs print the fleet size they actually executed. Competitor figures are their own published numbers and are labeled as such.

4. Iterations v1–v4

The headline results were reached by fixing real failures, each documented in the benchmark series:

5. Results

Target (north star)Result (measured, v4)Status
create → first exec ≤ 25 ms2.3 ms p50met (10× margin)
exec RTT ≤ 5 ms0.94 ms p50met
warm resume ≤ 50 ms~1 ms p50met
fork ≤ 20 ms1.55 ms p50met
RAM ≤ 25 MB / hot agent1.2 MBmet (20× margin)
≥ 2,000 agents at p99 exec < 50 ms2,000 @ 37.5 ms p99 (16 pods)met
Table 1. North-star targets vs. measured v4 results. AWS m7i.8xlarge, isolated-vm backend, true fleets, 8,000 ms heartbeat cadence.
Fleetv3 (sync, single)v4 single (p99)v4 × 16 pods (p99)
1,000203 ms28.2 ms19.9 ms
2,000400 ms52.9 ms37.5 ms
4,000810 ms109.2 ms73.8 ms
Table 2. Exec p99 under heartbeat load across iterations. RAM held ~1.2 MB/agent throughout.

6. Comparison with published figures

Different isolation models do not race one-for-one — a V8 isolate, a microVM, and a container make different trade-offs — so Table 3 should be read as where each model wins. Our numbers are measured; competitor numbers are their own published figures (provider docs and pricing pages, compiled July 2026).

MetricNaïve (measured)Field (published)
create → first exec2.3 msE2B <200 ms · Daytona ~90 ms · Modal ~1 s · Cloudflare 1–3 s · Firecracker boot 125 ms
warm resume / wake~1–2.4 msBlaxel 25 ms · Morph <250 ms · E2B ~1 s · Modal ~1 s
fork (copy-on-write)1.55 msMorph <250 ms · most providers: none published
RAM per resident agent1.2 MBE2B 512 MiB min · CF Containers 256 MiB min · CF Workers 128 MB per isolate, shared by co-tenants
idle-but-resident agentstorage only, no reserved RAMreserved-while-running vendors bill RAM every wall-clock hour
Table 3. Measured vs. published. Cold-create and snapshot-resume are compared like-for-like per row.

The density consequence is a shape rather than a headline number. An agent that is resident in about 1.2 MB sits two orders of magnitude below a microVM fleet's 256–512 MB floor, so what a host can hold is set by memory rather than by a per-agent machine allocation. The by-memory ceiling that follows from that is a modeled projection and stays internal; the density we are willing to state is the measured one, 2,000 concurrent agents at 37.5 ms p99. That gap is still the difference between “an agent per customer” being an infrastructure decision and being a rounding error.

7. What this runtime is for

Workloads that require arbitrary native binaries and a full Linux userland inside the sandbox — native compiler toolchains as the primary workload, in-sandbox services, headless browsers — are served by the burst tier rather than the resident loop; a machine-based sandbox runs those natively. The resident agent loop, at this density and cost, is the regime where the isolate model is uncontested.

8. Conclusion

Removing the machine from the sandbox changes the constants that agent infrastructure is built on: creation and forking become milliseconds, an idle agent becomes kilobytes, and what a host can hold is set by memory rather than by a per-agent machine allocation. The latency and density targets are met on real hardware, with a methodology that separates measured from published and prints the fleet that actually ran. The remaining work is optimization, not viability: driving 4,000+ concurrent agents under the 50 ms p99 bar (73.8 ms today), and widening the resident command surface by growing the WASM toolchain registry.

References

  1. Naïve Research. naive-sandboxes: benchmark results v1–v4 and methodology. github.com/usenaive/naive-sandboxes, July 2026.
  2. E2B. Sandbox lifecycle and pricing documentation. e2b.dev/docs, accessed July 2026.
  3. Modal. Sandboxes, memory snapshots, and pricing. modal.com/docs, accessed July 2026.
  4. Morph. Infinibranch: VM snapshot and branch documentation. morph.so, accessed July 2026.
  5. Cloudflare. Containers and Workers platform limits and pricing. developers.cloudflare.com, accessed July 2026.
  6. Vercel. Sandbox documentation and pricing. vercel.com/docs, accessed July 2026.
  7. Agache, A. et al. Firecracker: Lightweight virtualization for serverless applications. NSDI 2020.

Naïve figures measured on AWS m7i.8xlarge (Intel Xeon 8488C, 32 vCPU / 124 GB, Linux, Node 22.23), isolated-vm backend, July 2026. Competitor figures are their published numbers, compiled from provider documentation; different isolation models are compared like-for-like per operation. Full reports, raw artifacts, and methodology: github.com/usenaive/naive-sandboxes. Correspondence: team@usenaive.ai.

[Typeset version]

The same paper as a PDF, for citing and printing. The page you are reading is the version we correct first.

Download PDF