SimpleBox.exec() moves the execute step wholesale into the sandbox, so an agent’s rm -rf or unknown package install leaves the host untouched. Anything present in the image runs: python, node, go run, bash, your own binary.
Quick Example (minimal happy path)
The snippet below runs as-is. It starts an Alpine box, runs one command, and reads the result back.Common Usage
Set environment variables, working directory, and run user
Environment variables use a dict (not a list) and are injected for thisexec call:
Streaming / incremental output collection
SimpleBox.exec already collects stdout and stderr concurrently internally (to avoid the deadlock of a full pipe buffer) and returns them together when done. If you want truly line-by-line streaming (consume output while it runs), drill down to the lower-level Box (the SimpleBox internal handle box._box) to get the async iterator streams of an Execution:
Note:box._boxis an SDK-internal handle; the leading underscore signals “not public, but stable to use”. For most cases,await box.exec(...)and its aggregated result are enough; drill down toExecutiononly when you need to consume output as it runs (long-running task progress, log following).
Timeout control
SimpleBox.exec’s timeout parameter is timeout (float, seconds). A timeout does not raise a Python exception; the process is killed with SIGTERM and returns a negative exit code (-15, that is -SIGTERM) — check exit_code (negative / non-zero means it was killed). On this path, error_message is None; to detect a timeout, inspect exit_code:
Naming reminder: the wrapper-layerSimpleBox.execusestimeout(float); the lower-level nativeBox.execusestimeout_secs(see the streaming example above);CodeBox.runusestimeout(int).
Harden the box for untrusted code
The microVM boundary is always on. Two further knobs narrow what the code inside can reach — tighten the OS-level sandbox around the VM, and restrict where it can talk to.Details: Secrets and hardening and Network access.security=is not a top-level keyword — passing it directly raisesTypeError: BoxOptions.__new__() got an unexpected keyword argument 'security'. It must be wrapped inadvanced=AdvancedBoxOptions(security=...).
Parameters and Returns
SimpleBox.exec(cmd, *args, env=None, user=None, timeout=None, cwd=None)
Source: sdks/python/boxlite/simplebox.py:175
Returns
ExecResult (a dataclass, sdks/python/boxlite/exec.py:14):
Node equivalent: SimpleBox.exec(...)
Source: sdks/node/lib/simplebox.ts. Three overloads:
Returns
ExecResult = { exitCode: number; stdout: string; stderr: string } (camelCase exitCode). Node’s env is also an object, Record<string,string>, not an array.
Troubleshooting
Passing env as a list -> AttributeError / wrong behavior
SimpleBox.exec(env=...) expects a dict; internally it converts via env.items() (simplebox.py:220). Passing a list errors at the .items() call.
Note the distinction: theSimpleBox(...)constructor’s box-levelenv=takes a list of tuples (for exampleenv=[("USER","alice")]); whereasexec(env=...)takes a dict. The two layers differ — don’t mix them up.
A command failed but raised nothing
A non-zero exit code fromexec does not raise — this is by design (so an agent can self-check and decide based on it). Always check exit_code:
await box.exec("false") returns { exitCode: 1 } and does not reject.
Missing command / image pull failure -> standard RuntimeError / bare Error (not BoxliteError)
A missing command or an image pull failure raises a standard RuntimeError (Python) / bare Error (Node), not BoxliteError. See Error Handling.
Writing to /tmp, /dev/shm (tmpfs) and then not finding it
This is unrelated to exec but often shows up alongside it: copy_in to a tmpfs mount point (the same limitation as docker cp) may not be readable afterward. To get a file into /tmp, pipe a tar through exec, or write to a non-tmpfs path. See Moving files without a mount.
Don’t pack arguments into one string
exec("ls -l /") looks for "ls -l /" as a single program name and will fail. Split it into exec("ls", "-l", "/"), or go through a shell explicitly: exec("sh", "-c", "ls -l /").
Environment constraint: hardware virtualization required
Each BoxLite box is a microVM and needs underlying virtualization:- Linux: requires KVM (
/dev/kvmavailable); WSL2 needs KVM and the user in thekvmgroup. - macOS arm64: uses Apple’s Hypervisor.framework and needs no
/dev/kvm. macOS Intel is not supported. - Environments without virtualization (most CI containers) -> the box fails to start and raises a standard
RuntimeError(the process does not crash; it can be caught).

