Python SDK
The official Python SDK — spawn sandboxes, run code and commands, and move files. Mirrors the e2b Sandbox shape.
pip install qbox-sh
The SDK mirrors the e2b Sandbox shape, so migrating is mostly a one-line import
change.
A TypeScript SDK is coming soon. Until then, drive qbox from TypeScript via the REST API.
Authentication
The SDK reads QBOX_API_KEY and QBOX_BASE_URL from the environment, or you pass
them explicitly via qbox.configure(...):
export QBOX_API_KEY=qbox_...
export QBOX_BASE_URL=https://qbox.your-company.internal
import qbox
qbox.configure(api_key="qbox_...", base_url="https://qbox.acme.internal")
Create an API key in the dashboard under API Keys.
Quickstart
import qbox
with qbox.Sandbox.create(template="python-3.12") as sandbox:
# Run code in a stateful interpreter and read rich output.
result = sandbox.run_code("import pandas as pd; pd.DataFrame({'a':[1,2,3]}).describe()")
print(result.text)
# Run a shell command.
proc = sandbox.commands.run("python --version")
print(proc.stdout)
The with block kills the sandbox on exit. To keep it running, call
qbox.Sandbox.create(...) without the context manager and kill() when done.
Sandboxes auto-terminate after 5 minutes by default. Every sandbox has an auto-kill timeout (default 300 s, set server-side by
QBOX_DEFAULT_SANDBOX_TIMEOUT_SECONDS). Passtimeout=oncreateto change it, callset_timeout(seconds)to extend a running one, or passtimeout=0to disable the auto-kill entirely. Long-running work must raise this or it’ll be reaped mid-session.
Sandboxes
sandbox = qbox.Sandbox.create(template="python-3.12") # spawn (auto-kills after 5 min)
sandbox = qbox.Sandbox.create(template="python-3.12", timeout=3600) # 1-hour lifetime
sandbox = qbox.Sandbox.create(template="python-3.12", timeout=0) # never auto-kill
sandbox = qbox.Sandbox.connect("sb_018f…") # reconnect by id
info = sandbox.get_info() # status, template, host
sandbox.set_timeout(600) # extend the auto-kill window
for s in qbox.Sandbox.list(): # active sandboxes
print(s.id, s.status)
sandbox.kill()
Override the template’s defaults and shape the sandbox at spawn:
sandbox = qbox.Sandbox.create(
template="python-3.12",
cpu_count=2,
memory_mb=2048,
disk_size_mb=8192, # writable-disk ceiling in MB (sparse — you
# only pay for what's actually written)
envs={"OPENAI_API_KEY": "…"}, # env vars available to processes in the sandbox
allow_internet_access=False, # cut outbound egress (default: on)
)
Run code
run_code executes in a stateful kernel (variables persist across calls within a
context). Outputs can be text, HTML, PNG, or JSON.
out = sandbox.run_code("x = 40")
out = sandbox.run_code("print(x + 2)") # → 42; state carried over
print(out.text)
# Stream output as it's produced:
for event in sandbox.run_code_stream("for i in range(3): print(i)"):
print(event)
Commands
# Foreground — blocks, returns stdout/stderr/exit code.
proc = sandbox.commands.run("pytest -q")
print(proc.stdout, proc.exit_code)
# Background — returns a handle you can stream and kill.
handle = sandbox.commands.run("python server.py", background=True)
for line in handle: # stream combined output
print(line)
handle.kill()
sandbox.commands.list() # running processes
Files
sandbox.files.write("/tmp/data.csv", "a,b\n1,2\n")
sandbox.files.append("/tmp/data.csv", "3,4\n")
text = sandbox.files.read("/tmp/data.csv")
entries = sandbox.files.list("/tmp")
sandbox.files.mkdir("/tmp/out")
sandbox.files.upload("./local.bin", "/tmp/local.bin")
sandbox.files.download("/tmp/result.json", "./result.json")
sandbox.files.rename("/tmp/a", "/tmp/b")
sandbox.files.remove("/tmp/b")
print(sandbox.files.exists("/tmp/data.csv"))
Interactive shell
Install the extra and open a PTY straight into the VM (the template must have SSH enabled):
pip install "qbox[shell]"
sandbox.shell() # interactive PTY
Templates
for t in qbox.Templates.list():
print(t.id, t.name, t.status)
t = qbox.Templates.get("tpl_…")
Build from a git repository
Build a template straight from a public https git repo. If the repo has a
Dockerfile it’s built as-is; otherwise railpack infers a build. Identical
inputs hit a build cache and return a ready template instantly.
build = qbox.Templates.create_from_git(
"https://github.com/acme/myapp",
name="my-app",
ref="main", # branch, tag, or full commit SHA
# dockerfile_path is optional — omit to auto-detect a Dockerfile, else railpack
build_args={"NODE_ENV": "production"},
default_memory_mb=2048,
default_vcpus=2,
)
print(build.state, build.cache_hit, build.resolved_commit_sha)
template = build.wait_until_ready(timeout=600) # no-op on a cache hit
sandbox = qbox.Sandbox.create(template=template.template_id)
Browser sessions
Drive headful chromium over CDP with Playwright/Puppeteer. Create from a
browser-capable template (build one from the qbox/browser base image), wait
until ready, then connect.
import qbox
from playwright.async_api import async_playwright
browser = qbox.Browsers.create(template="tpl_…", viewport={"width": 1280, "height": 720})
browser.wait_until_ready(timeout=60)
async with async_playwright() as pw:
pw_browser = await pw.chromium.connect_over_cdp(browser.connect_url)
page = await pw_browser.contexts[0].new_page()
await page.goto("https://example.com")
print(await page.title())
browser.terminate()
By default a session ends when the controlling CDP connection disconnects
(Browserbase model). Pass keep_alive=True to survive disconnects until
timeout_seconds (default 1h, max 6h) or an explicit terminate(). The
live_view_url embeds an interactive view of the page in an iframe (it carries
the auto-login query, so it opens directly).
The live view (WebRTC) comes up a moment after CDP does. If you embed it the
instant a session goes ready, pass wait_for_live_view=True to create() so
wait_until_ready() holds until the live view is actually serving — automation-
only callers can leave it off so they connect as soon as CDP is up.
Errors
Every call raises typed errors so you can branch on the failure (auth,
not-found, conflict, transient, timeout). Transient errors are retried
automatically; the rest surface to you. See the package’s typed exceptions and
the examples/ directory in the SDK for end-to-end patterns.