Python SDK

pip install numinous. One client, five resources: templates, roms, sandboxes, usage, capacity. Errors are typed. Source: numinous-technology/numinous-python.

Client

from numinous import Numinous, NuminousError

nc = Numinous()                       # NUMINOUS_API_URL / NUMINOUS_API_KEY
nc = Numinous(api_url="...", api_key="nk_...")   # or explicit

Templates

tpl = nc.templates.pack("build-env",
                        image="ubuntu:24.04",
                        warm_cmd="apt-get update && apt-get install -y build-essential")
tpl = nc.templates.pack("from-dockerfile",
                        dockerfile=open("Dockerfile").read(), context=".")
nc.templates.list()
nc.templates.get(tpl["id"])["build_log"]   # durable build log

Sandboxes

sb = nc.sandboxes.create(
    template_id=tpl["id"],          # or image="..."
    rom_id=rom["id"],               # optional, mounts at /rom
    vcpu=4, mem_gib=8,
    ttl_seconds=7200,               # absolute; 0 = platform default
    launch_token="job-1-attempt-1", # idempotency
    labels={"trial_id": "tr_1"},
    egress="allowlist", allow=["api.anthropic.com"],
    env={"CI": "1"},
)

r = nc.sandboxes.exec(sb["id"], "make -j test",
                      timeout_sec=1800, cwd="/app", env={"V": "1"})
r["exit_code"], r["stdout"], r["duration_ms"]

nc.sandboxes.put_file(sb["id"], "/app/config.json", b"{}")
nc.sandboxes.get_file(sb["id"], "/app/out.log")
nc.sandboxes.logs(sb["id"], tail=200)

nc.sandboxes.suspend(sb["id"])      # scale to zero, storage cost only
nc.sandboxes.resume(sb["id"])       # same machine, processes intact

nc.sandboxes.export(sb["id"], "/logs", to="s3://bucket/tr_1/")  # works after death
out = nc.sandboxes.destroy(sb["id"])
out["teardown_proof"]["verified_absent"]   # True

nc.sandboxes.list(label="trial_id:tr_1", state="running")
nc.sandboxes.events(sb["id"])       # full audit trail
nc.sandboxes.wait(sb["id"], until="terminated", timeout=600)

Fan-out pattern

Reserve capacity first, boot N copies of one template with per-shard ROMs, then collect results by label.

nc.capacity.reserve(vcpu=2, mem_gib=4, count=200, duration_minutes=60)

shards = [nc.roms.create(f"shard-{i}", {"shard.txt": s}) for i, s in enumerate(split)]
boxes = [
    nc.sandboxes.create(template_id=tpl["id"], rom_id=r["id"],
                        vcpu=2, mem_gib=4, ttl_seconds=3600,
                        launch_token=f"suite-{run_id}-{i}",
                        labels={"run": run_id, "shard": str(i)})
    for i, r in enumerate(shards)
]
# ... exec, wait, export ...
nc.usage.query(label=f"run:{run_id}")["total_cost_usd"]

Typed errors

try:
    nc.sandboxes.create(...)
except NuminousError as e:
    e.cause               # "provider_capacity" | "user_image_build_failed" | ...
    e.status              # HTTP status
    e.is_provider_fault   # cause.startswith("provider_"): never billed
    e.retryable           # sane default retry policy