Run untrusted code on your own machine.

One Go binary and Docker. Create a sandbox, run a command, and keep the same API when you need a stronger backend.

import { Sandbox } from "@sbx.torsten.work/sbx"

const box = await Sandbox.create({
  template: "python",
  ttl: "5m",
})

await box.files.write("/workspace/main.py", "print(2 + 2)\n")
const result = await box.exec(["python", "main.py"])
console.log(result.stdout)
await box.kill()

One binary

A Go process, a SQLite file, and the Docker socket.

Closed by default

No network, no capabilities, uid 1000, a read-only rootfs, and a server-side TTL.

Agent inside

Streaming exec, background processes, a PTY, file watches, and preview ports.

Easy now, stronger later

Docker is the default. gVisor is that driver with runsc registered. Kata, Firecracker, and Kubernetes are planned. They keep this API.

BackendIsolationStatus
dockerNamespaces and cgroups. The default, on a machine that already has Docker.Ships
gvisorThe same Docker driver with the runsc runtime. No KVM. A missing runtime is an error.Ships, optional
kataA lightweight VM. The OCI image stays the same.Planned
firecrackerA microVM per sandbox.Planned
kubernetesWhatever RuntimeClass the cluster already runs.Planned

Build both binaries, then a request

Docker has to be running. Build sbx-agent next to sbx so the agent starts inside the sandbox. The first boot prints an admin key once and writes it to data/initial_api_key.

Templates are base, python, and node. The SDK reads SBX_URL and SBX_API_KEY. From this repo, node --experimental-strip-types examples/quickstart.ts runs on Node, and the same client runs on Bun.

go build -o sbx ./cmd/sbx
go build -o sbx-agent ./cmd/sbx-agent
./sbx serve

curl -s http://127.0.0.1:8080/v1/sandboxes \
  -H "Authorization: Bearer $SBX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template":"base"}'

curl -s http://127.0.0.1:8080/v1/sandboxes/$ID/exec \
  -H "Authorization: Bearer $SBX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cmd":["echo","hello"]}'

Install a release

A version tag publishes the binary, ghcr.io/torstendittmann/sbx, and @sbx.torsten.work/sbx. The npm name sbx is a different project.

Linux installs sbx and sbx-agent. macOS installs a darwin server and a linux agent, because the agent runs in the container. The image ships both and sets SBX_AGENT_BIN.

curl -fsSL https://raw.githubusercontent.com/TorstenDittmann/sbx/main/install.sh | sh
sbx version

docker run --rm -p 8080:8080 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v sbx-data:/data \
  ghcr.io/torstendittmann/sbx:latest

npm install @sbx.torsten.work/sbx
bun add @sbx.torsten.work/sbx

The calls you make

Send Authorization: Bearer sbx_…. Keys are stored hashed. A sandbox key only sees sandboxes it created. Processes, terminals, watches, and previews need sbx-agent. Without it those routes return unsupported, and exec and files use a shell in the image.

POST/v1/sandboxescreate
POST/v1/sandboxes/{id}/execwait, or SSE with ?stream=1
POST/v1/sandboxes/{id}/processesbackground command
POST/v1/sandboxes/{id}/terminalsPTY, then a WebSocket
GET/v1/sandboxes/{id}/files/watchfile events
POST/v1/sandboxes/{id}/previewsa port on the sandbox loopback
PUT/v1/sandboxes/{id}/files/contentupload
GET/healthzDocker reachable, or 503
GET/openapi.yamlthe contract

Limits

  • network: none is the default. full and allow reach the public internet, with DNS, allow and deny lists, and per-sandbox bandwidth. Metadata and private ranges stay blocked unless the operator opts out. Previews can be public or token-protected, including {port}-sbx-{id}.example.com.
  • disk_mb is the size of the writable /workspace tmpfs. The root filesystem is read-only, memory has no swap, and a PID limit applies.
  • Archives call tar in the image. Pause, resume, templates, quotas, and /metrics are real. A multi-node scheduler is not.