core

Sandboxes

A machine you keep. Sandbox() creates one and it stays up until you destroy it, so state survives between commands — installed packages, files you wrote, a process still running. It bills for as long as it exists, so delete() is what ends the meter.

create one

Every argument is a keyword and every one has a default, so you name only what you are changing. The two you will name most are the same two words the CLI prompts with — machine and environment. This is the full signature, with the value each argument takes when you leave it out:

sandbox.py
from boltzlabs import Sandbox

# every value below IS the default — Sandbox() alone is exactly this call
Sandbox(
    machine="small",       # nano | small | medium | large
    environment="base",    # runtimes: base | python | node | pytorch
                           # agents: opencode | claude-code | codex | deepagents | aider
    name=None,             # None -> the id the platform assigns
    internet=False,
    idle_timeout=None,     # seconds; None -> the platform's own
    max_lifetime=None,     # seconds; None -> the platform's own
)

So the common calls are short, and each one says what it is asking for:

usage.py
sb = Sandbox()                             # all defaults: small / base
sb = Sandbox(environment="python")         # machine stays small
sb = Sandbox(machine="medium", environment="pytorch", name="trainer")

sb.run("print(1)")                         # language follows the environment
sb.exec("pip install requests")            # a shell command
print(sb.url(8080))                        # public URL for a port inside

sb.delete()                                # stops the meter

An id is assigned by the platform, never chosen by you, so it is not a constructor argument — reach an existing sandbox with boltzlabs.sandbox(id) or by name. Use internet=True when you need ports.

ports.py
sb = Sandbox(internet=True, name="web")
sb.exec("python -m http.server 8000")

print(sb.url(8000))
# or from the CLI: bzlabs forward web 8000   (Ctrl-C to stop)

not forgetting to delete

A with block is the same three steps with the delete() written for you — including when line two raises, which is the case that otherwise leaves a machine billing until you notice.

with.py
with Sandbox() as sb:
    print(sb.run("print(sum(range(101)))"))

# destroyed here, however the block ended

results

run and exec return the same result. Print it and you get the output; test it and you get success.

result.py
print(sb.exec("ls"))              # prints stdout
if sb.exec("test -f /app/x"):     # True when the exit code was 0
    ...
sb.exec("make").check()           # raises if it failed

# .stdout .stderr .exit_code .duration_ms when you want them.
# A non-zero exit is data, not an exception: your program failed, not the call.

terminal

sb.terminal() is bzlabs connect: a real PTY, with the remote shell owning echo, arrow keys, tab completion and ^C. Pass a script instead and you get the transcript back — for commands that only behave correctly with a terminal attached.

terminal.py
sb.terminal()                                  # interactive
print(sb.terminal("tty; echo from-a-real-tty"))  # scripted

what you have

listing.py
import boltzlabs

boltzlabs.me()             # who your key belongs to      (bzlabs auth status)
boltzlabs.sandboxes()      # everything you have running  (bzlabs ls)
boltzlabs.sandbox(id)      # one of them, by id           (bzlabs status <id>)
boltzlabs.environments()   # runtimes and coding agents  (bzlabs environments)
boltzlabs.machines()       # machines and prices          (bzlabs machines)