Runbox Python SDK
Python client for Runbox, the lightweight sandbox for
agent commands and files. Standard library only — no requests, no build step.
pip install runbox-sdk
Quick start
import os
from runbox import Client, Identity
client = Client(
"http://localhost:8099",
api_key=os.environ["RUNBOX_API_KEY"],
identity=Identity(namespace="team-a", principal="user-42"),
)
result = client.exec('python3 -c "print(6 * 7)"', timeout=30)
print(result["exit_code"], result["stdout"]) # 0 42
The client is safe to reuse across threads: bind an identity once, or pass
identity= on any call.
Identity
Exactly one identity form per request:
| Form | Constructor | Headers sent |
|---|---|---|
| Opaque token | Identity(token="user-42") |
X-Runbox-Identity |
| Tenant + user | Identity(namespace="team-a", principal="user-42") |
X-Runbox-Namespace + X-Runbox-Principal |
Supplying both forms, or half of the scoped form, returns 400 from the
runner.
Run a command
result = client.exec(
"python3 analyze.py files/input.csv",
timeout=60,
files=[FileUpload(name="input.csv", path="input.csv")], # streamed from disk
)
with open("input.csv", "rb") as handle:
result = client.exec(
"cat files/input.csv",
files=[FileUpload(name="input.csv", stream=handle)], # streamed, never closed
)
Attachments land in files/<name> inside the workspace; the command refers to
them by that path. exec returns the parsed JSON response, including
exit_code, stdout, stderr, files and duration_ms.
Files
uploaded = client.upload_file("report.xlsx") # -> {"path": "files/report.xlsx", ...}
client.upload("notes.txt", b"hello")
client.upload_batch([FileUpload(name="a.csv", path="a.csv"), FileUpload(name="b.csv", path="b.csv")])
entries = client.list("out")
client.delete_workspace() # keeps the identity and its UID
Downloads can go to a path or to any file-like object:
client.download_path("out/report.csv", "report.csv")
client.download_path_to("out/report.csv", sink) # sink: anything with .write()
client.download_archive(["out", "tmp"], "artifacts.tar")
client.download_archive_to(["out"], sink)
Streaming and forwarding
open_path returns the raw http.client.HTTPResponse, so nothing is buffered.
iter_path yields chunks, which is what a framework response wants:
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
@app.get("/files")
def download(path: str):
return StreamingResponse(client.iter_path(path), media_type="application/octet-stream")
Forwarding a byte range (video scrubbing, resumable downloads) works the same
way; the runner answers with 206 and Content-Range, and the SDK passes the
body straight through:
@app.get("/files")
def download(path: str, range: str | None = None):
return StreamingResponse(client.iter_path(path, range_header=range))
A whole directory as one tar stream:
@app.get("/archive")
def archive():
return StreamingResponse(
client.iter_archive(["out", "tmp/step2"]),
media_type="application/x-tar",
headers={"Content-Disposition": 'attachment; filename="artifacts.tar"'},
)
If you need the response itself — headers, status, manual chunking — use
open_path / open_archive and close what you get back:
response = client.open_path("out/report.pdf", range_header="bytes=0-1023")
try:
print(response.status, response.getheader("Content-Length"))
for chunk in iter(lambda: response.read(65536), b""):
handle(chunk)
finally:
response.close()
Streaming stops when the client disconnects: the generator's finally closes
the response, and the runner notices the closed connection.
Health and limits
client.health()
client.ready()
client.capabilities() # limits and detected tooling
client.wait_ready(timeout=30)
client.metrics()
Errors
Every non-2xx response raises RunboxError with status, code and
message:
from runbox import RunboxError
try:
client.exec("rm -rf out && echo gone")
except RunboxError as error:
if error.code in ("busy", "quota_exceeded"):
... # retry later, or clean the workspace
elif error.code == "timeout":
... # raise the timeout
else:
raise
Common codes: 400 bad identity or path, 401 bad bearer token, 404 path
missing or owned by another identity, 409 busy / quota_exceeded, 413
request too large.
Links
- API reference: docs/api.md
- Deployment and hardening: docs/deployment.md
- Changelog: CHANGELOG.md
Metadata
Release files for runbox-sdk 0.2.4
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 |
|---|---|---|---|---|
| runbox_sdk-0.2.4.tar.gz | 14.2 kB | Without provenance | Details for runbox_sdk-0.2.4.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| runbox_sdk-0.2.4-py3-none-any.whl | Python 3 | none | any | Details for runbox_sdk-0.2.4-py3-none-any.whl |
Total release size: 25.0 kB
Release files / runbox_sdk-0.2.4.tar.gz
| Download URL | runbox_sdk-0.2.4.tar.gz |
|---|---|
| Size | 14.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc5368451455898c30c6126dc6aa14e4ed0eeb0e2c431b76de903524e798d123
|
|
BLAKE2b-256 checksum How to use checksums |
68bfec47122a0bde3e22bba2e4aa9e4e3a2b9c9e2f54a5e4665fcda218415457
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / runbox_sdk-0.2.4-py3-none-any.whl
| Download URL | runbox_sdk-0.2.4-py3-none-any.whl |
|---|---|
| Size | 10.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3c2e6900ef90ad24e351081c71687c3df04abf342a3c7da2a3e2b7d4f1e92403
|
|
BLAKE2b-256 checksum How to use checksums |
70eb992c8e7a7f6de6a6eb04a9ad8e33ec9933683a585a8ae23f982378c1c948
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Security for runbox-sdk 0.2.4
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.