Products

Sandboxes

Isolated microVM environments for running code from AI agents: exec, files, a Python kernel, port previews, SDK, MCP and the AI Gateway.

Sandboxes (Dashboard → project → Sandboxes) are on-demand isolated environments where an AI agent or your app can safely run arbitrary code. Each sandbox is its own machine: a microVM by default (Kata Containers + Cloud Hypervisor, its own kernel and KVM isolation) or gVisor (cheaper, faster start, user-space kernel). Sandboxes run only on the dedicated workers host, with no access to databases.

Quickstart

curl -X POST https://host.ulewicz.space/api/v1/projects/<ref>/sandboxes \
  -H "Authorization: Bearer $HOSTBASE_TOKEN" -H "Content-Type: application/json" \
  -d '{"template":"python-3.12"}'
# -> { "id": "sbx...", "state": "running", "timings": { "total_ms": 40, "from_pool": true }, ... }

curl -X POST .../sandboxes/<id>/exec -H "Authorization: Bearer $HOSTBASE_TOKEN" \
  -d '{"cmd":"python3 -c \"print(1+1)\""}'
# -> { "exit_code": 0, "stdout": "2\n", "stderr": "" }

curl -X DELETE .../sandboxes/<id> -H "Authorization: Bearer $HOSTBASE_TOKEN"

Templates

IdNameContents
python-3.12Python 3.12 (data science)numpy, pandas, matplotlib, scipy, scikit-learn, seaborn; Jupyter-like kernel with PNG charts and HTML tables
node-22Node.js 22Node.js 22 LTS, npm, git, build tools
bunBun 1Bun runtime, package manager, test runner
ubuntuUbuntu 24.04 (base)Ubuntu 24.04 + Python 3, pip, git, curl, jq, build-essential
playwright-chromiumPlaywright + ChromiumPlaywright with Chromium/Firefox/WebKit (headless browser automation)

Limits and plans

Defaults: 1 vCPU, 1024 MB RAM, 5 GB disk (/workspace), shutdown after 5 minutes idle (idle_timeout_s, 30 s – 24 h; API calls, preview traffic and CPU load of 10% of a vCPU or more reset the counter) and after 1 h of lifetime at most (lifetime_s, up to 24 h). /workspace is a separate fixed-size ext4 image - writes beyond the limit fail with "No space left".

Planmax vCPUmax RAMmax diskmax lifetimeconcurrentincluded (vCPU-h / GB-h)
free11024 MB2 GB1 h25 / 10
pro24096 MB20 GB24 h10100 / 200
team48192 MB50 GB24 h40500 / 1000

Exec and streaming

POST …/exec takes cmd (a string run with bash -c, or an argv array), cwd, env, timeout_s (default 60) and stdin. With "stream": true the response is an SSE stream of {"type":"stdout"|"stderr"|"exit",…} events. With "background": true the process starts detached (output goes to a log file), e.g. an HTTP server. Environment variables set at creation apply to every call. The interactive terminal (xterm.js) lives in the dashboard; in the API use terminal + the SSE stream + input.

Files

Relative paths resolve under /workspace. files/list, files/content (raw bytes, GET/PUT/DELETE), files/mkdir and files/archive (tar - bulk upload and directory download). Single-file limit: 256 MB.

Running code (kernel)

POST …/run-code with {"code": "…", "language": "python"} behaves like a notebook cell: the Python kernel (templates python-3.12 and ubuntu) keeps state across calls with the same context_id. The response holds results: stdout, stderr, the last expression's value (text/plain), text/html tables (pandas), matplotlib charts as image/png (base64) and an error object with the traceback. For javascript (Node/Bun) and bash every run is stateless.

Port preview URLs

Any sandbox port is reachable at https://<id>-<port>.sbx.workers-waw1.host.ulewicz.space (TLS, WebSockets supported). Previews are public by default (the URL contains a random id); with "preview": "private" a token is required (x-hostbase-sandbox-token header or ?hb_token=, returned at creation). Responses carry X-Robots-Tag: noindex. Requests to the URL count as activity (they reset the idle timeout).

Pause and resume

pause in freeze mode freezes the machine in memory (resume takes tens of ms and processes survive; only half the RAM rate is billed, no CPU). stop mode stops the machine and frees its RAM but keeps the /workspace disk (resume is a ~2 s cold start, processes do not survive). A paused sandbox expires after 24 h.

Egress policy

  • open - the internet is reachable (default);
  • allowlist - only the listed hostnames or IP/CIDR (names are resolved and refreshed every 5 min; DNS to 1.1.1.1 / 8.8.8.8 is allowed);
  • none - no outbound traffic.

Always blocked regardless of mode: private networks (RFC1918, including the database hosts), the cloud metadata service, other sandboxes' networks, port 25 and ports typical for crypto miners (stratum).

Metrics, logs, usage

metrics returns samples every 10 s (CPU, memory, network, processes) and disk usage; logs - lifecycle events and the kernel log; usage - monthly project and organization usage against the plan allowance.

Billing

You pay for reserved resources while the sandbox runs: vCPU-seconds and GB-seconds of RAM. Included: Free 5 vCPU-h and 10 GB-h (hard limit), Pro 100 / 200, Team 500 / 1000. Beyond that: 0.25 PLN net per vCPU-hour and 0.04 PLN per GB-hour. Lines appear in Costs and on the invoice.

Security model

  • Isolation: Kata + Cloud Hypervisor microVMs - a separate guest kernel and a hardware (KVM) boundary; gVisor as an option. Code cannot see the host or other sandboxes.
  • Network: a separate bridge and subnet per sandbox; no access to private networks, the cloud metadata service, databases or other sandboxes.
  • Resources: hard CPU, memory, PID and disk limits, forced shutdown after idling and after the maximum lifetime.
  • Abuse: we detect pegged CPU, miner processes and stratum connection attempts. A sandbox running a miner is shut down and the owner is notified.
  • Secrets: a sandbox gets no project keys - only the env variables you pass explicitly.

Token scopes

sandboxes:read (list, metrics, logs, usage) and sandboxes:write (create, exec, files, terminal, close); sandboxes:* grants both. Among project roles owner, admin and developer can write; readonly only reads.

Management API

GET|POST   /api/v1/projects/{ref}/sandboxes                       (?all=1 includes recently ended)
GET        /api/v1/projects/{ref}/sandboxes/templates
GET        /api/v1/projects/{ref}/sandboxes/usage
GET|DELETE /api/v1/projects/{ref}/sandboxes/{id}
POST       /api/v1/projects/{ref}/sandboxes/{id}/pause          { mode: "freeze" | "stop" }
POST       /api/v1/projects/{ref}/sandboxes/{id}/resume
POST       /api/v1/projects/{ref}/sandboxes/{id}/timeout        { idle_timeout_s, lifetime_s }
POST       /api/v1/projects/{ref}/sandboxes/{id}/egress         { mode: "open"|"allowlist"|"none", hosts }
POST       /api/v1/projects/{ref}/sandboxes/{id}/ports          { port }
POST       /api/v1/projects/{ref}/sandboxes/{id}/exec           { cmd, cwd, env, timeout_s, stdin, stream, background }
POST       /api/v1/projects/{ref}/sandboxes/{id}/run-code       { code, language, context_id, timeout_s }
GET        /api/v1/projects/{ref}/sandboxes/{id}/files/list?path=
GET|PUT|DELETE /api/v1/projects/{ref}/sandboxes/{id}/files/content?path=
POST       /api/v1/projects/{ref}/sandboxes/{id}/files/mkdir?path=
GET|PUT    /api/v1/projects/{ref}/sandboxes/{id}/files/archive?path=   (tar)
GET        /api/v1/projects/{ref}/sandboxes/{id}/metrics
GET        /api/v1/projects/{ref}/sandboxes/{id}/logs
POST       /api/v1/projects/{ref}/sandboxes/{id}/terminal       { cols, rows } -> { session_id }
GET        /api/v1/projects/{ref}/sandboxes/{id}/terminal/{sid}/stream   (SSE, base64 chunks)
POST       /api/v1/projects/{ref}/sandboxes/{id}/terminal/{sid}/input    { data, base64 }
POST       /api/v1/projects/{ref}/sandboxes/{id}/terminal/{sid}/resize   { cols, rows }
DELETE     /api/v1/projects/{ref}/sandboxes/{id}/terminal/{sid}

TypeScript SDK

import { Sandbox } from "@hostbase/sandbox";

const sbx = await Sandbox.create({ apiKey: process.env.HOSTBASE_TOKEN!, project: "<ref>", template: "python-3.12", timeoutS: 600 });
const r = await sbx.exec("ls -la /workspace");               // { exitCode, stdout, stderr }
await sbx.files.write("/workspace/hello.py", "print('hi')");
const text = await sbx.files.read("/workspace/hello.py");
const run = await sbx.runCode("import numpy as np; np.arange(5).sum()");
await sbx.close();

A Python SDK skeleton lives in the repository (sdk/sandbox-python).

MCP

Tools for Claude Code, Cursor and other agents: create_sandbox, sandbox_exec, sandbox_run_code, sandbox_write_file, sandbox_read_file, list_sandboxes and close_sandbox. They require the sandboxes:write scope (listing: sandboxes:read).

AI Gateway: code_interpreter

Add "hostbase_tools": ["code_interpreter"] to a request to /api/ai/v1/chat/completions. The gateway gives the model a tool that runs Python in a sandbox of your project (a stateful kernel; charts come back as images) and drives the tool loop for up to 4 rounds; the sandbox is closed when the response finishes.

Start-up performance

For each template we keep a small warm pool of default-sized microVMs (1 vCPU / 1 GB / 5 GB). Creating a sandbox with default parameters claims a ready machine (tens of milliseconds); custom parameters or an empty pool mean a cold start (~2 s). The timings field in the response shows which path was taken.

Measured on host-workers-waw1 (D4as_v5, 4 vCPU / 16 GB)

StepMedian / range
Create, warm pool (default size, microVM)12-29 ms
First exec after create (docker exec round-trip)130-200 ms
Create, cold microVM (python / ubuntu / node / bun / playwright)1.9-2.1 s / 1.8-1.9 s / 1.6 s / 1.6 s / 1.6 s
Create, cold gVisor (python / ubuntu)0.65 s / 0.60 s
Management API POST /sandboxes end-to-end (warm)~260 ms
Pause (freeze) / resume41-46 ms / 37-48 ms
Pause (stop) / resume (VM boot)0.54 s / 1.4 s
run-code Python, first call (imports pandas + matplotlib) / next call2.5 s / 0.12 s
Close (destroy VM, disk, network)0.63-0.68 s

Warm pool: 3 x python-3.12, 2 x ubuntu, 2 x node-22 (refilled in the background, ~2 s each). Cold numbers include creating the per-sandbox bridge, the ext4 disk image, booting the Kata + Cloud Hypervisor VM and waiting for the guest agent.