boax
Python SDK for Boax, the self-hosted sandbox and microVM platform. Python 3.9 or newer, standard library only.
Your code asks for a profile, capabilities and a placement policy. Boax picks the pool; the SDK never needs to know which backend runs the sandbox.
Install
pip install boax
Until the package is published, install from a checkout: pip install ./sdk/python.
Quickstart
from boax import Boax
# Defaults: BOAX_API_KEY and BOAX_URL (or http://localhost:8080).
client = Boax()
# Waits until the sandbox is running; pass wait=False to return at once.
sandbox = client.sandboxes.create(
profile="small",
placement={"strategy": "private-first", "external": "never"},
)
result = sandbox.exec("uname -sm") # a string runs via /bin/sh -c
print(result.exit_code, result.stdout)
sandbox.exec(["ls", "-la", "/work"], cwd="/work", timeout_seconds=30) # a list runs directly
sandbox.files.write("/work/a.txt", "hi")
text = sandbox.files.read_text("/work/a.txt")
sandbox.delete()
A sandbox is also a context manager that deletes itself on exit:
with client.sandboxes.create(profile="small") as sandbox:
print(sandbox.exec("uname -a").stdout)
Streaming output
import sys
for ev in sandbox.exec_stream("make test"):
if ev.type == "stdout":
sys.stdout.write(ev.data)
elif ev.type == "stderr":
sys.stderr.write(ev.data)
elif ev.type == "exit":
print("exit code", ev.exit_code)
else:
print("backend error:", ev.error)
The command starts when exec_stream is called. The iterator ends after
exit or error. If the connection drops before either arrives, it raises a
connection_error.
Errors
Every failure is a BoaxError with code, status, details and
request_id. Branch on code, not on the message.
from boax import BoaxError
try:
client.sandboxes.create(profile="gpu-large")
except BoaxError as err:
if err.code != "quota_exceeded":
raise
print("over quota on", err.details.get("dimension"), "request", err.request_id)
Server codes include invalid_request, unauthenticated, permission_denied,
not_found, conflict, quota_exceeded, no_eligible_pool,
unsupported_capability, unsupported_operation, provider_unavailable,
invalid_state, rate_limited, suspended and internal. The SDK adds
timeout and connection_error (with status 0). Waiting raises
invalid_state if the sandbox fails or terminates first.
Retries. GET, PUT and DELETE requests, and sandbox creation, are retried
up to max_retries times (default 3). Retries happen on 503, on 429
rate_limited (never quota_exceeded) and on connection errors, with
exponential backoff that respects Retry-After. Each create call sends its
own Idempotency-Key, so a retried create never makes a second sandbox. Pass
idempotency_key to keep the key stable across process restarts. Exec
and other POSTs are never retried.
What's covered
| Namespace | Methods |
|---|---|
sandboxes |
create, get, list, iterate, update, delete, wait |
Sandbox handle |
exec, exec_stream, files.list/read/read_text/write, stop, start, pause, resume, snapshot, fork, expose_port, explain_placement, refresh, update, wait, delete |
snapshots |
list, get, delete |
projects |
list, create, get, delete |
api_keys |
list, create, revoke |
quotas, usage |
get |
audit_events |
list, iterate |
policies |
list, put, delete |
capabilities, profiles, templates, classifications |
list |
admin |
organizations.{list,create,get,update,suspend,resume}, projects.set_quota, pools.{list,get,create,update,drain,undrain,delete}, agents.list, trust_report, verify_audit, terminate_sandbox, reconcile |
| client | me, version |
Keyword arguments are snake_case. Records come back as plain dicts keyed exactly
like the API's JSON (camelCase), typed with TypedDict in boax.types.
ExecResult, ExecEvent and Page are dataclasses.
list returns one Page (items, next_cursor); iterate walks every page:
for sb in client.sandboxes.iterate(status="running", labels={"team": "ml"}):
print(sb.id)
Options
Boax(
api_key="dly_...", # default: BOAX_API_KEY
base_url="https://...", # default: BOAX_URL, then http://localhost:8080
timeout=120.0, # socket timeout in seconds; waits and streams set their own
max_retries=3,
headers={}, # extra headers on every request
)
Plain exec uses the client timeout unless you pass timeout_seconds. For long
commands, pass timeout_seconds or use exec_stream, which has no socket
timeout.
Development
python3 -m unittest discover -s tests # runs against an in-process http.server
Metadata
Release files for boax-py 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| boax_py-0.1.0.tar.gz | 23.6 kB | Without provenance | Details for boax_py-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| boax_py-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for boax_py-0.1.0-py3-none-any.whl |
Total release size: 45.1 kB
Release files / boax_py-0.1.0.tar.gz
| Download URL | boax_py-0.1.0.tar.gz |
|---|---|
| Size | 23.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
aa05a545f457e12dd6df586981d18b273ba3376e8d59e70d41cb757bf853a736
|
|
BLAKE2b-256 checksum How to use checksums |
e6cccb2db83c803b67590881b83f88541becf8686f9c128e866420392696cb1f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / boax_py-0.1.0-py3-none-any.whl
| Download URL | boax_py-0.1.0-py3-none-any.whl |
|---|---|
| Size | 21.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
15cdc242fe1a7b26128e9d93431525f0ffc015d17f6271d6593778ba12677775
|
|
BLAKE2b-256 checksum How to use checksums |
ca2d551a1341bd0d54951b2ba924b1a50c2e0fe6150f5f95d1a59ee71ce7cbd2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for boax-py 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.