Containers

Run the code your agent writes.

Lean microVMs that start and exit in seconds, a fresh, isolated machine for every interpreter turn, tool call and CI shard. Fan out hundreds at once, each with its own kernel, billed by the second, free while paused.

npm i @sandal/sdk
code-interpreter.tsCreate → exec → fan out
import { Sandal } from "@sandal/sdk";
const sandal = new Sandal({ apiKey: process.env.SANDAL_API_KEY });
// A lean container, booted from a warm pool in well under a second.
const box = await sandal.sandboxes.create({
runtime: "container",
template: "python-3.12",
resources: { vcpus: 1, memoryMb: 2048 },
});
// Run the code the model just wrote.
const run = await box.exec("python analysis.py");
console.log(run.exitCode, run.stdout);
// Fan out: fork a warm parent instead of re-installing 200 times.
const workers = await Promise.all(
Array.from({ length: 50 }, () => box.fork())
);
<1scold start
<200mswarm claim
$0.0045per container-hr, from
1kernel each
$0while paused
What it’s for

Built for code that runs once and exits.

A container is the right shape when the work is short, parallel and disposable, the code an agent generates, not a machine it lives on.

Code interpreter

Run what the model wrote.

Run model-generated Python, JS or shell against a real machine and stream the result back into context. The worst case is a wasted container, not a shared host.

const box = await sandal.sandboxes.create({
runtime: "container", template: "python-3.12",
});
const run = await box.exec(`python -c '${modelOutput}'`);
messages.push({ role: "tool", content: run.stdout });
Agent tool calls

A machine per turn.

The model proposes a command, the container runs it, the output returns. Pause between turns and the idle time is free, resume is sub-second, with the filesystem exactly as it was.

for await (const turn of agent.run(task)) {
await box.resume(); // < 200ms
const out = await box.exec(turn.command);
turn.observe(out.stdout, out.exitCode);
await box.pause(); // $0 while thinking
}
Untrusted code

Nothing it does leaves the box.

Arbitrary code from users or an LLM runs in its own kernel with default-deny egress. Nothing it does reaches the host, another tenant or the internet unless you allow it.

const box = await sandal.sandboxes.create({
runtime: "container",
template: "node-24",
network: {
egress: ["registry.npmjs.org"], // everything else: denied
inject: [{ host: "api.github.com",
header: "Authorization", secret: "gh_pat" }],
},
});
CI fan-out

Install once, fork many.

Shard a test suite across hundreds of containers that start on a merge and tear straight down. Fork a warm parent so you pay the install once, not per shard, a fork is a generation-graph operation, not a disk copy.

Start rate 60/s: a 400-shard job starts 400 containers. The fleet is sized for the spike, not the average.

shard.ts
// pay the install a single time
const base = await sandal.sandboxes.create({ template: "web-ci" });
await base.exec("pnpm install --frozen-lockfile");
// then branch it, each fork is a graph op, not a copy
const shards = await Promise.all(
Array.from({ length: 8 }, () => base.fork())
);
await Promise.all(
shards.map((s, i) => s.exec(`pnpm test --shard=${i + 1}/8`))
);
The problem

Regular containers share one kernel.

A standard container runs on the host’s kernel next to everyone else’s. That shared kernel is an escape route you patch forever instead of removing. Running code you didn’t write, from a user or a model, right beside your own workload is a bet that eventually goes wrong.

Shared kernel = shared blast radius

One container escape reaches the host and its neighbours. A microVM has its own kernel, so there is nothing next door to escape into.

Secrets leak through the filesystem

A token written into the guest is a token the code can read. Injecting it at the edge keeps it out of the guest entirely.

Deletion you have to trust

Wiping a disk is a step that can fail. Destroying the only key that decrypts it leaves unrecoverable ciphertext, nothing to trust.

How it works

A fresh, locked-down
machine per run.

Boot in under a second, run the code behind its own kernel, take the result, and leave nothing behind.

interpreter.ts
const box = await sandal.sandboxes.create({
runtime: "container",
template: "python-3.12",
network: { egress: [] }, // default deny, reaches nothing
});
const run = await box.exec(`python -c '${untrustedCode}'`);
console.log(run.stdout, run.exitCode);
// destroy, the per-box key goes with it, so nothing is recoverable
await box.destroy();
  1. 01

    Start with no access

    A microVM starts with no outbound network and its own isolated stack. It can reach nothing, not the host, not another customer, not the internet.

  2. 02

    Run the code

    Execute the untrusted code against its own kernel. The worst case is a wasted machine, not a compromised host or a leaked secret.

  3. 03

    Take the result

    Read stdout, stderr and the exit code, or pull a file off the disk. Outbound access opens only for the specific hosts you allow.

  4. 04

    Leave nothing behind

    Releasing the machine destroys the encryption key unique to it. Whatever is left in storage is ciphertext no one can read.

Concurrency

Hundreds at once, install paid once.

High concurrency is the whole point of a container fleet. The trap is re-installing dependencies in every one, 500 boxes a day is 500 billable installs. Do the expensive part once in a parent, then fork; each fork starts from the finished disk in milliseconds.

Fork, don’t reinstall

Near-constant cost per child.

A fork is a generation-graph operation, not a disk copy. Every child starts from the parent’s finished disk with a new ID, new tokens and its own clock.

Start rate 60/s

Sized for the spike.

A 400-shard job starts 400 containers. Warm pools keep the claim time flat as the burst grows; the fleet is sized for the peak, not the average.

Paused is free

A slow agent costs nothing.

Between turns a container pauses to $0 and resumes sub-second, so the idle minutes while a model thinks never touch the meter.

Plans

One balance. Every machine you run.

Containers draw from the same credit pool as your VMs, runners and simulators, billed by the second at one published rate card.

Starter

For a solo build or a first agent in production.

$20/ month

$20 of usage credits

≈ 550 VM-hours or 33,000 CI minutes

Get started
  • 20 concurrent machines
  • Committed in-plan rates on every product
  • Linux & Windows, sandboxes, VMs, runners
  • Per-second billing, paused is free
  • Full API, SDKs, CLI & MCP server
  • Unlimited seats
  • Community support
Most popular

Team

Apple silicon unlocked, and a balance that rolls over.

$100/ month

$100 of usage credits

≈ 2,700 VM-hours or 10,000 Mac build minutes

Get started
  • 100 concurrent machines
  • Everything in Starter, plus:
  • macOS, iOS/Android simulators & Xcode builds
  • Unused credits roll over one month
  • Usage exports & per-second line items
  • Email support

Business

Higher ceilings for a team leaning on the fleet daily.

$250/ month

$250 of usage credits

≈ 6,900 VM-hours or 25,000 Mac build minutes

Get started
  • 300 concurrent machines
  • Everything in Team, plus:
  • Raised concurrency & start rate
  • Priority support & shared Slack channel
  • Single sign-on (SAML / OIDC)
  • Volume credit rate

Enterprise

Dedicated capacity, your compliance surface, one invoice.

Custom

Committed volume rate

Committed volume rate, negotiated per account

Talk to sales
  • Reserved bare-metal capacity
  • BYOC or self-host the control plane
  • SSO & SCIM, audit logs, data residency
  • Annual invoicing, MSA, DPA
  • Support SLA & solutions engineering
  • Custom regions on request

Every plan spends its credit pool first, then usage keeps flowing and bills per second at your committed in-plan rate, no hard stop mid-run, no forced upgrade. Without a plan you pay the on-demand rate instead. Prices are illustrative pending final list pricing; the per-second billing model is final.

Rate card

The container rate card.

Linux

MachineIn-plan / container-hrOn-demand / container-hr
0.5 vCPU / 1 GB$0.0045$0.0067
1 vCPU / 2 GB$0.009$0.013
2 vCPU / 4 GB$0.018$0.027
4 vCPU / 8 GB$0.036$0.054
8 vCPU / 16 GB$0.072$0.108
16 vCPU / 32 GB$0.144$0.216

Priced from the Linux formula: $0.0065 / vCPU-hr + $0.00125 / GB-hr. Any vCPU:RAM combination in between is priced the same way. On-demand is 1.5× the in-plan rate. All usage bills by the second; paused machines are not billed.

Get started

Give your AI agents somewhere to run today.

Your agents get their own machines across Linux, macOS, Windows, iOS and Xcode in milliseconds, and you stop paying for idle.

npx sandal init