Skip to main content
E2B

E2B sandboxes → the Naive compute primitive

E2B gives an AI agent a real, isolated Linux box in the cloud: call Sandbox.create(), then run shell commands, execute model-generated code, and read/write files — all in a container that is firewalled from your own infrastructure. It does that job well, the spin-up is fast, and the SDK is mature. But the sandbox is also a separate vendor account:
  • Every sandbox lives behind an E2B_API_KEY, its own dashboard, and its own billing — disconnected from wherever the agent’s email, cards, secrets, and KYC live.
  • The key is all-or-nothing: anything holding it can spawn a box and commands.run() arbitrary shell. There is no per-action gate — no “this agent may run code but a human must approve a shell session.”
  • “Who let this agent execute that, and what else can it touch?” is answered in E2B for sandboxes, and in unrelated systems for everything else. The box has no shared accountability with the rest of the agent’s footprint.
Naive’s compute primitive gives the agent the same capability — an isolated cloud container it can exec into and run code in — but the workload is rooted in one governed identity:
  • The tenant user that owns the workload is the same user that owns its email inboxes, its cards, its vault secrets, and its KYC.
  • The agent never holds a cloud key. Naive owns the underlying cloud credentials and scopes every task to your tenant — the same model as Apps.
  • Whether an agent may spin up a workload at all, and whether opening a shell (exec/ssh) freezes for human approval, is decided by that user’s Account Kit at execution time — and every shell session is transcript-logged.
This guide maps E2B’s sandbox model to Naive’s compute primitive, shows the smallest working swap, and is explicit about what does not map yet — and E2B’s code-interpreter and filesystem APIs are the parts to read carefully.
E2B is a trademark of its owner, used here for identification only. No endorsement or affiliation is implied.
Tested against: the E2B JavaScript SDK e2b v2.30.x (Sandbox.create, sandbox.commands.run, sandbox.files.*, sandbox.getHost, sandbox.kill; base https://api.e2b.dev) and the code-interpreter SDK @e2b/code-interpreter (sandbox.runCode) — docs snapshot June 2026 — and the Naive Node SDK @usenaive-sdk/server against the Naive API (base https://api.usenaive.ai/v1, docs snapshot June 2026).Version notes:
  • E2B ships two packages: base e2b (Sandbox + commands + files) and @e2b/code-interpreter (adds runCode(), a stateful Jupyter-style kernel with rich outputs). Naive maps the commands.run / exec-a-process model; the runCode kernel does not map yet — see what doesn’t map yet.
  • E2B’s unit is an ephemeral sandbox with a default 5-minute timeout (max 1h Hobby / 24h Pro), spun up from a template (the base image, or a custom one built with the E2B CLI). Naive’s unit is a workload built from any Docker image you bring — a long-running service, a run-to-completion job, or a cron schedule — with no template build step.
  • E2B identifies a box by its sandboxId and can pause/resume to preserve full memory+filesystem state. Naive identifies a workload by its id and offers scale-to-zero (stop/start), which is not a memory snapshot — see gaps.
  • On Naive, creating a workload and exec/ssh are sensitive — depending on the user’s Account Kit they may return { status: "pending_approval", approval_id }. E2B has no equivalent execution-time gate.

Concept map

Before / after: the core path

The path that matters for almost every code-running agent is get an isolated box, run a command, read the output back, tear it down. Here it is on both platforms.
The shape is close — get a box, run a process, read output via the exec channel — but the real differences to plan for:
  • You bring the image; you hold no key. E2B spins up from a template under your E2B_API_KEY. Naive runs any Docker image you pass, on cloud credentials it owns — the agent never holds a cloud key.
  • The box is long-running, not auto-killed. An E2B sandbox auto-kills at its timeoutMs. A Naive service runs until you stop (scale to zero) or destroy it. Use a job for run-to-completion work.
  • exec is a governed action. A commands.run in E2B is ungated. On Naive, exec/ssh is sensitive: depending on the Account Kit it may return pending_approval and is transcript-logged.
  • The id is your identity, not a separate account. In E2B the key scopes E2B. In Naive the same forUser(id) handle also owns the agent’s email, cards, vault, and KYC.

The workflow that actually changes: running model-generated code

This is where the two models diverge most. E2B’s headline is the code interpreter: runCode() executes a snippet in a stateful kernel and hands back rich outputs (stdout, results, charts). Naive has no code-interpreter kernel — you run code by exec-ing a process inside an image that already has the runtime. The capability (run untrusted, model-generated code in an isolated box) maps; the ergonomics differ.
  • No stateful kernel. Each exec is a fresh process — variables do not persist between calls the way they do across runCode invocations. Hold state in the image’s filesystem or an external store.
  • No rich result objects. runCode returns structured results (charts, dataframes); exec returns a managed session — read process output from the stream. If you rely on inline charts/images, that is a gap.
  • The win is custody, not ergonomics. The runtime, its secrets, and its shell now live under one identity with execution-time approval and a unified log — not behind a standalone key.

Minimal viable migration

The smallest swap that keeps a working code-running agent alive is get a box → run a command → read output → tear down.
1

Install the SDK and set your key

Set NAIVE_API_KEY (a server-side key from the dashboard). You can drop E2B_API_KEY for this path.
2

Pick an image instead of a template

Replace the E2B template with a Docker image that has your runtime (python:3.12-slim, node:22-slim, or your own). Push custom images to a registry and pass them as image. There is no template build step to manage.
3

Swap sandbox creation

Replace Sandbox.create({ timeoutMs }) with client.compute.create({ name, type: "service", image, command: ["sleep", "infinity"] }). Keep the returned workload id. (Use type: "job" with a command for run-to-completion work.)
4

Swap command execution

Map sandbox.commands.run(cmd)client.compute.exec(id, cmd). Handle a possible pending_approval result if the Account Kit gates exec, then connect to the returned exec session for output. For an interactive session use client.compute.shell(id) (or naive compute ssh <id>).
5

Swap teardown

Replace sandbox.kill() with client.compute.destroy(id). For a box you want to reuse cheaply, client.compute.stop(id) scales it to zero (billing stops) and start(id) wakes it.
6

Ship it

At this point you are off E2B for the core get-box → run → read → teardown path. Everything below is upside, not a requirement.

Consolidate further once you’re on Naive

This is where the migration pays for itself. In E2B, the API key isolates sandboxes and nothing else, and any code the agent runs executes behind a key with no per-action gate. On Naive, the unit of isolation is a tenant user, and compute is one of many primitives that identity owns.

Gain #1 — one identity across primitives

  • With E2B, the agent’s sandboxes are an island behind an API key, and any secret you inject is one you store, rotate, and protect yourself. With Naive, naive.forUser(acme.id) is a single handle to compute and email and cards and vault and KYC.
  • The container’s secrets are not loose env vars — they are encrypted under the identity that owns everything else. Tear the customer down from one place; sibling tenants can never read each other’s workloads, secrets, cards, or logs.

Gain #2 — execution-time permission enforcement

  • Whether an agent may run compute at all, and whether opening a shell freezes for human review, is policy on the identity — not a key scope you manage in a second console, and not a check you hand-write.
  • The agent’s code is identical for every tier — client.compute.exec(...), client.compute.create(...). Whether the call runs is decided at execution time:
    • Creating a workload and exec/ssh are sensitive. With approval on, the call returns { status: "pending_approval", approval_id } and runs only after a human approves it.
    • The agent holds no cloud key. Naive owns the underlying cloud credentials; the workload is scoped to your tenant, so a leaked agent key can’t spawn boxes on your raw cloud account.
    • Shell access is transcript-logged over a managed exec channel (no port 22, no SSH keys).

Gain #3 — unified accountability

  • Every workload, run, exec, and shell session for a customer lands in one per-user activity log — alongside their email, card, vault, and KYC events, not in a separate E2B dashboard:
  • That is the question that is hard to answer when code execution lives in E2B, secrets live in your own manager, cards live in Stripe, and email lives somewhere else. Under Naive it is a single query.

What does not map yet

A migration guide that hides gaps is worse than none. The core path (create → exec → read → teardown), secrets, jobs, schedules, and a public-port service map cleanly. But the following E2B capabilities have no direct equivalent on Naive’s compute primitive today — and a couple are central to how many teams use E2B. Check this list against your app before you commit.
If your agent depends on E2B’s code-interpreter kernel (runCode with persistent state and rich chart/result objects), its filesystem API, or pause/resume memory snapshots, those are the gaps most likely to block a clean migration — Naive’s compute is a Docker-image workload you exec into, not a stateful interpreter with a filesystem SDK. If the interpreter kernel is the core of your product, keep E2B for that path and adopt Naive compute for the workloads that fit. The flip side is the gain: the container, its secrets, and its shell are governed by the same identity and Account Kit as the rest of the agent — with execution-time approval and a unified audit trail — not a standalone account behind an all-or-nothing key.

Where to go next

  • compute primitive — service / job / schedule, secrets, logs, shell
  • compute SDK sub-client — typed method signatures
  • compute CLI — create / run / logs / ssh / exec
  • Queue — pair a service with a queue for a cheap autoscaling worker
  • Apps — the same “agent never holds a cloud key” model for managed infra
  • Account Kits and Approvals — the policy model behind execution-time governance and exec approval
  • Tenant users — the identity that owns the compute, email, cards, and vault