Documentation
Compute & sandboxes
Isolated boxes for running code your agent wrote or can’t trust: Modal for cheap one-off runs (and the only GPU path), plus five stateful session sandboxes — E2B, Daytona, Vercel, Runloop, Fly — where installs, files, and process state persist across commands. One rule above all: every box you open must be torn down — an abandoned sandbox keeps billing until it stops.
Reach for compute only when you actually need to *run code* — untrusted or AI-generated code, data-processing scripts, test suites in isolation, temporary batch jobs, or validating generated code before showing it to a user. If you just need data, a search or scraping call is cheaper and faster; if you need to click and type in a real browser, that’s the Browser service.
When to use which
| Need | Call | Price | Pick when |
|---|---|---|---|
| Quick one-off run | modal/sandbox-create → sandbox-exec → sandbox-terminate | ~3¢ + 1¢ + 1¢ | The default. A single execute-and-read, ≤300s. |
| GPU run (inference / CUDA) | modal/sandbox-create with gpu | ~2–21¢ by tier | The only GPU path. |
| Stateful multi-step session | e2b/create_session | ~5¢/vCPU-hr | The default stateful box — Firecracker microVM isolation for untrusted code. |
| Stateful, fastest cold start | daytona/create_session | ~5¢/vCPU-hr | ~30–90ms starts; Docker isolation, so trusted code only. |
| Stateful, microVM isolation | vercel/create_session | ~5¢/vCPU-hr | Firecracker microVM; US-East only, sessions ≤5h. |
| Coding-agent devbox | runloop/create_session | ~5¢/vCPU-hr | Persistent devbox with snapshot/resume. |
| Long-running, $0 when idle | fly/create_session | 7¢/CPU-hr + 4.375¢/GB-hr | State must survive and idle time should cost nothing. |
The routing rule: default to Modal for a one-off execute-and-read — it’s per-call, cheap, and ephemeral. Escalate to a stateful session when the work is multi-step (installs + iteration), needs filesystem state to carry between commands, or runs longer than Modal’s 300-second lifetime.
modal/sandbox-create
- Price
- ≤5¢ CPU (bills the actual price, ~3¢) · GPU by tier
- Latency
- slow — container startup; GPU images slower still
- Lifetime
- up to 300s by default
Creates a sandboxed environment and returns its sandbox_id. All params are optional: image (defaults to a slim Debian container), command (an optional entrypoint run at startup), timeout (max lifetime in seconds, default 300), and gpu (one of T4, L4, A10G, A100, H100 — omit for CPU).
GPU sandboxes
Pass gpu to get a GPU-backed box — this is the path for model inference and CUDA workloads. GPU creates bill the actual price under tiered caps; set max_cost_cents to the tier’s cap so a price move can’t surprise you.
| Tier | Typical | Cap (set max_cost_cents here) |
|---|---|---|
T4 | ≈2–5¢ | 25¢ |
L4 | — | 30¢ |
A10G | — | 40¢ |
A100 | ≈21¢ | 150¢ |
H100 | — | 250¢ |
curl -X POST https://vaaya.ai/api/run/modal/sandbox-create \
-H "Authorization: Bearer $VAAYA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image": "python:3.12", "gpu": "T4", "max_cost_cents": 25}'Gotchas
- The sandbox has a hard timeout (default 300s). If your code takes longer, raise
timeout— or it gets killed mid-run. - Each create costs ~3¢ even if the startup command fails instantly — validate your command before sending.
- CPU is the default; only pass
gpuwhen the workload actually needs one.
modal/sandbox-exec
- Price
- 1¢
- Latency
- depends on the command
- Returns
{ stdout, stderr, returncode }
Runs a command inside a sandbox created with sandbox-create and returns its output — this is how you actually *use* a sandbox. sandbox_id and command are required; timeout (seconds) is optional. command may be a shell string (run via sh -c, so pipes, quotes, and && work) or an argv array like ["python", "-c", "print(1)"] (no shell).
# 1) create the box — returns only { "sandbox_id": "sb-..." }
curl -X POST https://vaaya.ai/api/run/modal/sandbox-create \
-H "Authorization: Bearer $VAAYA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image": "python:3.12"}'
# 2) run code and read the output
curl -X POST https://vaaya.ai/api/run/modal/sandbox-exec \
-H "Authorization: Bearer $VAAYA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-abc123", "command": "echo hello && python --version"}'
# → { "stdout": "hello\nPython 3.12.x\n", "stderr": "", "returncode": 0 }
# 3) tear down
curl -X POST https://vaaya.ai/api/run/modal/sandbox-terminate \
-H "Authorization: Bearer $VAAYA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-abc123"}'- The sandbox must still be running (within its
timeoutwindow) — exec against a terminated or expired sandbox fails. Create → exec → terminate.
modal/sandbox-status and modal/sandbox-terminate
- Price
- 1¢ each
- Latency
- fast
sandbox-status checks whether a sandbox is running, finished, or failed (sandbox_id is the only param). sandbox-terminate stops it and frees its resources.
- Status costs 1¢ per check — don’t poll in a tight loop. Check once after a reasonable delay.
- Always terminate when done — abandoned sandboxes keep burning balance until they hit their timeout.
Stateful sessions
- Price
- ~5¢/vCPU-hr metered (Fly: 7¢/CPU-hr + 4.375¢/GB-hr, $0 idle)
- Lifecycle
create_session→session(repeat) →close- State
- filesystem + installs persist across commands
Five providers share one lifecycle. Opening a box is a normal HTTP call to POST /api/run/{provider}/create_session — it returns { session_id } immediately and reserves a small credit hold, released in full when you close. Optional params: template and envs. The box then stays alive — and metered — until you close it or your balance runs out, at which point it is force-closed.
curl -X POST https://vaaya.ai/api/run/e2b/create_session \
-H "Authorization: Bearer $VAAYA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"template": "base"}'
# → { "session_id": "..." }Running commands in the box and closing it happen through the session and close tools on the MCP surface — connect with the same key. session takes session_id plus either command (a shell string) or code with an optional language (python, the default, javascript, or bash), and returns stdout/stderr/exit code. The same box is reused across calls, so installs and files persist.
# run — repeat as needed; the SAME box is reused between calls
session({ "session_id": "...", "command": "pip install pandas && python analysis.py" })
# close — required; stops the meter and settles. Idempotent.
close({ "session_id": "..." })Which stateful sandbox
| Provider | Price | Isolation | Pick when |
|---|---|---|---|
e2b | ~5¢/vCPU-hr | Firecracker microVM | The default — untrusted or hostile code. |
daytona | ~5¢/vCPU-hr | Docker | Cold-start latency matters (~30–90ms) and the code is trusted. |
vercel | ~5¢/vCPU-hr | Firecracker microVM | Strong isolation; US-East only, sessions ≤5h. |
runloop | ~5¢/vCPU-hr | devbox | A persistent coding-agent devbox with snapshot/resume. |
fly | 7¢/CPU-hr + 4.375¢/GB-hr · $0 idle | sprite | Long-running work where state must survive and idle is free. |
e2b
The default stateful box: Firecracker microVM isolation, so it’s the right home for untrusted or hostile code. Metered by uptime at ~5¢/vCPU-hr.
daytona
The fastest cold start (~30–90ms). template picks the language: python (default), typescript, or javascript. Daytona has a stateful interpreter — variables persist across code calls, not just the filesystem.
- Isolation is Docker, not a microVM — prefer E2B for hostile untrusted code.
vercel
A Firecracker microVM with strong isolation, metered by wall-clock uptime (~5¢/vCPU-hr) whether the box is busy or idle. US-East only, sessions capped at 5 hours.
- No stateful interpreter —
coderuns as a one-shot subprocess, so in-memory variables do not persist betweencodecalls. Use the filesystem or shell commands to carry state. python3availability depends on the runtime — prefer a shellcommandfor non-JS work unless you know the box has the interpreter.
runloop
A persistent coding-agent devbox with snapshot/resume; slower cold start than Daytona. Metered by uptime at ~5¢/vCPU-hr.
- No stateful interpreter —
coderuns viapython3 -c/node -e, so language-level variable state does not persist acrosscodecalls (filesystem and installed packages do).
fly
A persistent sprite: filesystem, installed packages, and process state survive across commands, and it is $0 when idle — you pay only CPU-hr + GB-hr while it’s actively running (7¢/CPU-hr + 4.375¢/GB-hr at the default 1 CPU / 1 GB size).
- No auto-expire. If you forget to
close, nothing self-stops the box — closing it is on you. envsis not applied at create on Fly today —exportenv vars inside asessioncommand instead.coderuns one-shot (python3 -c/node -e): in-memory variables don’t persist acrosscodecalls, though filesystem and installed packages do.
To stage inputs into a box or keep its outputs, pair sessions with Files & storage — upload once, download inside the sandbox from the file’s URL.