Skip to main content
BoxLite runs any command or untrusted code inside a lightweight virtual machine, giving you process-level isolation, fast startup, and no exposure of the host system. Typical scenarios include an AI agent executing LLM-generated code, multi-tenant execution of user-submitted scripts, and running untrusted builds in CI.

Prerequisites

  • The boxlite Python package and a machine with hardware virtualization — see Installation.
Install:
Verify the install (prints the installed version, which should be the latest published version; you can also check with pip show boxlite):

Quick Example (shortest path)

Save the following as hello.py and run it with python hello.py. It is a complete, standalone script: it pulls an image, starts a Box, runs a command, prints the result, and cleans up automatically.
Expected output:
The first run downloads the python:alpine image and may take tens of seconds; later runs hit the local cache and start quickly.
What happens:
  1. BoxLite pulls the python:alpine OCI image (first run only).
  2. It starts a lightweight microVM from that image.
  3. It runs python -c "..." inside the VM.
  4. It streams stdout / stderr / exit code back to the host process.
  5. On exit from async with, it stops and removes the Box automatically.

Next Step: Executing Untrusted Code (CodeBox)

CodeBox is a subclass of SimpleBox with a built-in Python image. It provides run() to run code directly and install_package() to install dependencies dynamically — the typical pattern for an AI agent executing LLM-generated code. Save this as codebox.py:
CodeBox.run(code) returns the stdout string, whereas SimpleBox.exec(...) returns an ExecResult object (with exit_code / stdout / stderr). Do not confuse the two.

Parameters and Returns

Common SimpleBox(...) constructor parameters

SimpleBox is lazily created: the constructor only validates arguments; the actual create/start happens when you enter async with.
Note: cpus and memory_mib default to None, which means BoxLite applies the runtime’s default VM size rather than a value you set. To see the actual resources inside a Box, run nproc and read /proc/meminfo inside it. In production, set the resources explicitly. See Compute resources.

box.exec(cmd, *args, ...) parameters

ExecResult (the return value of box.exec)

Listing and cleanup (runtime methods live on the runtime)

Listing and removing Boxes are methods on the runtime (Boxlite), not on a Box:
Boxlite is entered with a synchronous with, and the Boxlite.default() factory is synchronous too. Its instance methods (list_info() / create() / get() / remove() / metrics() / shutdown()) are async — always await them, or you get RuntimeError: no running event loop. The one exception is box.info(), which is synchronous (do not await it).

Troubleshooting

ValueError: Either 'image' or 'rootfs_path' must be provided

The SimpleBox constructor requires either image or rootfs_path. CodeBox has a built-in default image (python:slim), so you do not pass image.

A command exited non-zero but no exception was raised

exec does not raise on a non-zero exit code; it returns ExecResult(exit_code != 0). You must check it yourself:

RuntimeError: image pull failure / startup failure without virtualization

On a network failure during the image pull or when the environment has no hardware virtualization, a standard builtins.RuntimeError is raised (not BoxliteError). Catch it with try/except RuntimeError and retry:

Environment constraint: hardware virtualization required

  • macOS (Apple Silicon): uses the built-in Hypervisor.framework, needs no /dev/kvm, and works out of the box.
  • Linux: needs KVM (/dev/kvm present and accessible).
  • WSL2: needs KVM enabled and the user in the kvm group.
  • No virtualization: the Box fails to start (the exception is catchable; the process does not crash).
  • macOS Intel: not supported.

Confusing dict and list for environment variables

box.exec(env=...) takes a dict: env={"FOO": "bar"}. The SimpleBox constructor parameter env= (passed through to BoxOptions) takes a list of tuples: env=[("FOO", "bar")]. The two layers use different formats; do not confuse them.

Next Steps

Now that you have your first sandbox, you can continue with:
  • Reuse and lifecycle: use name + reuse_existing=True to reuse the same Box across sessions; manage Boxes with runtime.list_info() / runtime.remove(id, force=False).
  • Specialized boxes: BrowserBox (Playwright browser automation), ComputerBox (desktop automation), InteractiveBox (interactive PTY shell), and SkillBox (running Claude Code).
  • Resources and isolation: use BoxOptions to configure cpus/memory, volumes, ports, an egress allowlist, and secrets, plus security presets via advanced=AdvancedBoxOptions(security=...).
  • Other languages: see the Node.js quickstart, the Rust quickstart, and the Go quickstart.