Python SDK for zerobox. Sandbox any command with file, network, and credential controls.
pip install zeroboxInstalling the wheel drops the zerobox CLI into your environment's bin/ and exposes a Python SDK.
For CLI usage, secrets concepts, the full flag reference, performance numbers, and platform support see the main README.
from zerobox import Sandbox
sandbox = Sandbox.create({"allow_write": ["/tmp"]})
print(sandbox.sh("echo hello").text())Three ways to run a command. Each returns a ShellCommand you terminate with .text(), .json(), or .output().
name = "world"
sandbox.sh(f"echo hello {name}").text()data = sandbox.py("import json; print(json.dumps({'sum': 1 + 2}))").json()sandbox.exec("python3", ["-c", "print('hi')"]).text()| Method | On success | On non-zero exit |
|---|---|---|
.text() |
Returns stdout as a string | Raises SandboxCommandError |
.json() |
Parses stdout as JSON | Raises SandboxCommandError |
.output() |
Returns CommandOutput(code, stdout, stderr) |
Returns the same shape, never raises |
data = sandbox.sh("cat data.json").json()
result = sandbox.sh("exit 42").output()
# CommandOutput(code=42, stdout='', stderr='')Use AsyncSandbox in async applications so waiting for the sandboxed subprocess
does not block the event loop. The command shape is the same as Sandbox, but
creation and terminators are awaited.
from zerobox import AsyncSandbox
sandbox = await AsyncSandbox.create({"allow_write": ["/tmp"]})
text = await sandbox.sh("echo hello").text()
data = await sandbox.sh("printf '{\"ok\": true}'").json()
result = await sandbox.exec("python3", ["-c", "print('hi')"]).output()Async commands accept the same timeout option:
import subprocess
try:
await sandbox.sh("sleep 60").text(timeout=1.0)
except subprocess.TimeoutExpired:
print("cancelled")Non-zero exit raises SandboxCommandError:
from zerobox import Sandbox, SandboxCommandError
sandbox = Sandbox.create()
try:
sandbox.sh("exit 1").text()
except SandboxCommandError as e:
print(e.code, e.stderr)Pass API keys that the sandboxed process never sees. The proxy substitutes the real value only for approved hosts.
import os
from zerobox import Sandbox
sandbox = Sandbox.create({
"secrets": {
"OPENAI_API_KEY": {
"value": os.environ["OPENAI_API_KEY"],
"hosts": ["api.openai.com"],
},
"GITHUB_TOKEN": {
"value": os.environ["GITHUB_TOKEN"],
"hosts": ["api.github.com"],
},
},
})
sandbox.sh('curl -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/models').text()See the main README for how placeholder substitution works.
Record filesystem changes and roll them back automatically:
sandbox = Sandbox.create({
"allow_write": ["."],
"restore": True,
})
sandbox.sh("npm install").text()Record without rolling back:
sandbox = Sandbox.create({
"allow_write": ["."],
"snapshot": True,
"snapshot_exclude": ["node_modules"],
})
sandbox.sh("npm install").text()Pass a timeout (seconds) to any terminator:
import subprocess
try:
sandbox.sh("sleep 60").text(timeout=1.0)
except subprocess.TimeoutExpired:
print("cancelled")sandbox = Sandbox.create({
"env": {"NODE_ENV": "production"},
"allow_env": ["PATH", "HOME"],
"deny_env": ["AWS_SECRET_ACCESS_KEY"],
})See the main README for what's inherited by default and the CLI equivalents.
Sandbox.create(options) accepts a SandboxOptions dataclass or a plain dict. All fields are optional.
| Field | Type | Description |
|---|---|---|
profile |
str | list[str] |
Named profile(s). A list merges left-to-right. Default "workspace". |
allow_read / deny_read |
list[str] |
Readable / blocked paths. |
allow_write / deny_write |
list[str] |
Writable / blocked paths. |
allow_net |
bool | list[str] |
True allows all. A list restricts to those domains. |
deny_net |
list[str] |
Blocked domains. |
allow_all |
bool |
Full filesystem + network access. |
no_sandbox |
bool |
Disable the sandbox entirely. |
strict_sandbox |
bool |
Fail instead of falling back to weaker isolation. |
cwd |
str |
Working directory. |
env |
dict[str, str] |
Explicit env vars. |
allow_env |
bool | list[str] |
Inherit parent env vars. |
deny_env |
list[str] |
Blocked env vars. |
snapshot |
bool |
Record filesystem changes. |
restore |
bool |
Record and roll back after exit. Implies snapshot. |
snapshot_paths / snapshot_exclude |
list[str] |
Tracked paths / excluded patterns. |
secrets |
dict[str, SecretConfig] |
Secrets with per-host scopes. |
debug |
bool |
Print sandbox config to stderr. |
Unknown dict keys (e.g. accidental allowWrite instead of allow_write) raise TypeError at construction time.
Sandbox.py(code) runs whichever python3 is on PATH inside the sandbox. If your active interpreter lives outside the sandbox's readable roots (for example uv-managed Pythons under ~/.local/share/uv/), fall back to:
import sys
sandbox = Sandbox.create({"allow_read": [sys.prefix]})
sandbox.exec(sys.executable, ["-c", "print('hi')"]).text()- TypeScript SDK (npm:
zerobox) - Rust SDK (crates.io:
zerobox)
Apache-2.0