Complete API reference for the BoxLite Python SDK.
Python: 3.10+ Platforms: macOS (Apple Silicon), Linux (x86_64, ARM64)
- Runtime Management
- Box Handle
- Network Tunnels
- Command Execution
- Box Types
- Sync API
- Error Types
- Metrics
- Constants
The main runtime for creating and managing boxes.
from boxlite import Boxlite, Options, BoxOptions, ImageRegistry| Method | Signature | Description |
|---|---|---|
default() |
() -> Boxlite |
Create runtime with default settings (~/.boxlite) |
__init__() |
(options: Options) -> Boxlite |
Create runtime with custom options |
| Method | Signature | Description |
|---|---|---|
create() |
async (options: BoxOptions, name: str = None) -> Box |
Create a new box |
get() |
async (box_id: str) -> Optional[Box] |
Reattach to an existing box by ID |
get_info() |
async (box_id: str) -> Optional[BoxInfo] |
Get current box metadata by ID or name |
list_info() |
async () -> List[BoxInfo] |
List all boxes |
metrics() |
async () -> RuntimeMetrics |
Get runtime-wide metrics |
# Default runtime
runtime = Boxlite.default()
# Custom runtime
runtime = Boxlite(Options(home_dir="/custom/path"))
# Registry host config with auth
runtime = Boxlite(Options(
image_registries=[
ImageRegistry(
host="registry.example.com",
username="user",
password="password",
)
]
))
# Create a box
box = await runtime.create(BoxOptions(image="alpine:latest"))
# List all boxes
for info in await runtime.list_info():
print(f"{info.id}: {info.state.status}")Runtime configuration options.
| Field | Type | Default | Description |
|---|---|---|---|
home_dir |
str |
~/.boxlite |
Base directory for runtime data |
image_registries |
List[ImageRegistry] |
[] |
Registry transport, TLS, search, and auth configuration |
ImageRegistry(
host="registry.local:5000",
transport="http",
search=True,
)
ImageRegistry(
host="registry.example.com",
skip_verify=True,
username="user",
password="password",
)
ImageRegistry(
host="ghcr.io",
bearer_token="token",
)| Field | Type | Default | Description |
|---|---|---|---|
host |
str |
Required | Registry host, optionally with port. Do not include http:// or https:// |
transport |
str |
"https" |
"https" or "http" |
skip_verify |
bool |
False |
Disable TLS certificate and hostname verification for HTTPS registries |
search |
bool |
False |
Include this host when resolving unqualified image references |
username / password |
str | None |
None |
Basic auth credentials. Provide both together |
bearer_token |
str | None |
None |
Bearer token auth |
Configuration options for creating a box.
| Field | Type | Default | Description |
|---|---|---|---|
image |
str |
Required | OCI image URI (e.g., "python:slim", "alpine:latest") |
cpus |
int |
1 |
Number of CPU cores (1 to host CPU count) |
memory_mib |
int |
512 |
Memory limit in MiB (128-65536) |
disk_size_gb |
int | None |
None |
Persistent disk size in GB (None = ephemeral) |
working_dir |
str |
"/root" |
Working directory inside container |
env |
List[Tuple[str, str]] |
[] |
Environment variables as (key, value) pairs |
volumes |
List[Tuple[str, str, str]] |
[] |
Volume mounts as (host_path, guest_path, mode) |
network |
NetworkSpec | None |
None |
Structured network configuration. Omit for default enabled networking. |
ports |
List[Tuple | Dict] |
[] |
Local TCP forwarding; omit host_port in a dict for automatic allocation |
secrets |
List[Secret] |
[] |
Outbound HTTP(S) secret substitution rules |
advanced |
AdvancedBoxOptions | None |
None |
Expert-only options, including capabilities.add and capabilities.drop |
auto_remove |
bool |
True |
Auto cleanup when stopped |
detach |
bool |
False |
Survive parent process exit |
Capability policy is intentionally nested with the other expert-only options:
from boxlite import AdvancedBoxOptions, BoxOptions, ContainerCapabilities
options = BoxOptions(
image="alpine:latest",
advanced=AdvancedBoxOptions(
capabilities=ContainerCapabilities(
add=["NET_BIND_SERVICE"],
drop=["NET_RAW"],
)
),
)from boxlite import NetworkSpec
network = NetworkSpec(
mode="enabled",
allow_net=["api.openai.com"],
)| Field | Type | Default | Description |
|---|---|---|---|
mode |
str |
Required | "enabled" or "disabled" |
allow_net |
List[str] |
[] |
Outbound allowlist used only when mode="enabled" |
mode="disabled" removes the guest network interface entirely.
volumes=[
("/host/config", "/etc/app/config", "ro"), # Read-only
("/host/data", "/mnt/data", "rw"), # Read-write
]ports=[
(8080, 80, "tcp"), # HTTP
(5432, 5432, "tcp"), # PostgreSQL
{"guest_port": 3000}, # OS-selected host port
]Port publication is local-only and TCP-only. For portable local/remote access,
use box.network.tunnel(port); each tunnel handle represents one connection.
from boxlite import Secret
secrets=[
Secret(
name="openai",
value="sk-...",
hosts=["api.openai.com"],
# placeholder defaults to "<BOXLITE_SECRET:openai>"
)
]Handle to a running or stopped box.
| Property | Type | Description |
|---|---|---|
id |
str |
Unique box identifier (ULID format) |
network |
NetworkHandle |
Box-scoped tunnel operations |
| Method | Signature | Description |
|---|---|---|
exec() |
(cmd, args, env, tty) -> Execution |
Execute command (async) |
stop() |
() -> None |
Stop the box gracefully (async) |
remove() |
() -> None |
Delete box and its data (async) |
info() |
async () -> BoxInfo |
Get box metadata |
metrics() |
() -> BoxMetrics |
Get resource usage metrics (async) |
Metadata about a box.
| Field | Type | Description |
|---|---|---|
id |
str |
Unique box identifier (ULID) |
name |
str | None |
Optional user-assigned name |
state |
BoxStateInfo |
Runtime state with status, running, and nullable pid fields |
created_at |
str |
ISO 8601 creation timestamp |
image |
str |
OCI image used |
cpus |
int |
Allocated CPU cores |
memory_mib |
int |
Allocated memory in MiB |
network |
NetworkInfo | None |
Current network configuration and resolved local publications |
NetworkInfo has mode: str, allow_net: List[str], and
published_ports: List[PublishedPort] | None. Each PublishedPort has named
guest_port, host_ip, host_port, and protocol attributes.
network is None means network information is unavailable. Within
NetworkInfo, published_ports is None means the current handle does not know
the lifecycle's publications, [] means there are no active publications, and
a populated list contains concrete active local bindings. BoxOptions.ports
remains the request API; its optional host port is not reused in resolved output.
box.info() has no synchronous variant. Local metadata reads report
bindings captured when this handle started or reattached the box; REST metadata
reads fetch the current server record. A newly loaded local running box has no
live binding data yet, so box, get, or list info may report
published_ports is None until an operation requiring live state reattaches it.
Detailed state information for a box.
| Value | Description |
|---|---|
Created |
Box created but not yet started |
Starting |
Box is initializing |
Running |
Box is running and ready |
Stopping |
Box is shutting down |
Stopped |
Box is stopped |
Failed |
Box encountered an error |
Both boxlite.Box and boxlite.SimpleBox expose box.network.
| Operation | Signature | Description |
|---|---|---|
| Prepare | await box.network.tunnel(port) -> BoxTunnel |
Prepare one connection to a TCP service in the box |
| Inspect | tunnel.endpoint() -> str | int |
Return the remote URI or borrowed local file descriptor |
| Connect | await tunnel.connect() -> BoxConnection |
Consume the tunnel and return its bidirectional byte stream |
| Read/write | await connection.read(max_bytes), await connection.write(data) |
Exchange bytes with the service |
| Close | await connection.close() |
Close the connection |
Each BoxTunnel carries exactly one connection. Call tunnel() again for each
additional or concurrent connection. This differs from BoxOptions.ports,
which creates a persistent, local-only host listener that accepts repeated
connections from ordinary host applications.
Represents a running command execution.
| Method | Signature | Description |
|---|---|---|
stdout() |
() -> ExecStdout |
Get stdout stream (async iterator) |
stderr() |
() -> ExecStderr |
Get stderr stream (async iterator) |
stdin() |
() -> ExecStdin |
Get stdin writer |
wait() |
() -> ExecResult |
Wait for completion (async) |
kill() |
(signal: int = 9) -> None |
Send signal to process (async) |
resize_tty() |
(rows: int, cols: int) -> None |
Resize PTY terminal for executions started with tty=True (async) |
# Execute with streaming output
execution = await box.exec("python", ["-c", "for i in range(5): print(i)"])
# Stream stdout
async for line in execution.stdout():
print(f"Output: {line}")
# Wait for completion
result = await execution.wait()
print(f"Exit code: {result.exit_code}")Async iterators for streaming output.
# Stream stdout line by line
stdout = execution.stdout()
async for line in stdout:
print(line)
# Stream stderr
stderr = execution.stderr()
async for line in stderr:
print(f"Error: {line}", file=sys.stderr)Note: Each stream can only be iterated once. After iteration, the stream is consumed.
Writer for sending input to a running process.
| Method | Signature | Description |
|---|---|---|
send_input() |
(data: bytes) -> None |
Write bytes to stdin (async) |
# Interactive input
execution = await box.exec("cat")
stdin = execution.stdin()
# Send data
await stdin.send_input(b"Hello\n")
await stdin.send_input(b"World\n")
# Wait for completion
result = await execution.wait()Result of a completed execution.
| Field | Type | Description |
|---|---|---|
exit_code |
int |
Process exit code (0 = success) |
Note: For higher-level APIs (SimpleBox.exec()), the result also includes stdout and stderr strings.
Context manager for basic command execution with automatic cleanup.
from boxlite import SimpleBoxSimpleBox(
image: str,
memory_mib: int = None,
cpus: int = None,
runtime: Boxlite = None,
name: str = None,
auto_remove: bool = True,
**kwargs
)| Parameter | Type | Default | Description |
|---|---|---|---|
image |
str |
Required | Container image to use |
memory_mib |
int |
System default | Memory limit in MiB |
cpus |
int |
System default | Number of CPU cores |
runtime |
Boxlite |
Global default | Runtime instance |
name |
str |
None | Optional unique name |
auto_remove |
bool |
True |
Remove box when stopped |
**kwargs |
Additional options: env, volumes, ports, working_dir, network, secrets |
| Property | Type | Description |
|---|---|---|
id |
str |
Box ID (raises if not started) |
| Method | Signature | Description |
|---|---|---|
start() |
() -> Self |
Explicitly start the box (async) |
exec() |
(cmd, *args, env=None, user=None, timeout=None, cwd=None) -> ExecResult |
Execute command and wait (async) |
info() |
async () -> BoxInfo |
Get box metadata |
shutdown() |
() -> None |
Shutdown and release resources |
async with SimpleBox(image="python:slim") as box:
result = await box.exec("python", "-c", "print('Hello!')")
print(result.stdout) # "Hello!\n"
print(result.exit_code) # 0
# Per-command options
result = await box.exec("pwd", cwd="/tmp") # working directory
result = await box.exec("whoami", user="nobody") # run as user
result = await box.exec("sleep", "60", timeout=5) # timeout in secondsSpecialized box for Python code execution with package management.
from boxlite import CodeBoxCodeBox(
image: str = "python:slim",
memory_mib: int = None,
cpus: int = None,
runtime: Boxlite = None,
**kwargs
)| Method | Signature | Description |
|---|---|---|
run() |
(code: str, timeout: int = None) -> str |
Execute Python code (async) |
run_script() |
(script_path: str) -> str |
Execute Python script file (async) |
install_package() |
(package: str) -> str |
Install package with pip (async) |
install_packages() |
(*packages: str) -> str |
Install multiple packages (async) |
async with CodeBox() as cb:
# Install packages
await cb.install_package("requests")
# Run code
result = await cb.run("""
import requests
print(requests.get('https://api.github.com/zen').text)
""")
print(result)Box configured for browser automation with Chrome DevTools Protocol.
from boxlite import BrowserBox, BrowserBoxOptions| Field | Type | Default | Description |
|---|---|---|---|
browser |
str |
"chromium" |
Browser type: "chromium", "firefox", "webkit" |
memory |
int |
2048 |
Memory in MiB |
cpu |
int |
2 |
Number of CPU cores |
| Browser | Port |
|---|---|
| chromium | 9222 |
| firefox | 9223 |
| webkit | 9224 |
| Method | Signature | Description |
|---|---|---|
endpoint() |
() -> str |
Get CDP endpoint URL |
from boxlite import BrowserBox, BrowserBoxOptions
opts = BrowserBoxOptions(browser="chromium", memory=4096)
async with BrowserBox(opts) as browser:
endpoint = browser.endpoint() # "http://localhost:9222"
# Connect with Puppeteer or Playwright
# puppeteer.connect({ browserURL: endpoint })Box with full desktop environment and GUI automation capabilities.
from boxlite import ComputerBoxComputerBox(
cpu: int = 2,
memory: int = 2048,
gui_http_port: int = 3000,
gui_https_port: int = 3001,
runtime: Boxlite = None,
**kwargs
)| Method | Signature | Description |
|---|---|---|
mouse_move() |
(x: int, y: int) -> None |
Move cursor to coordinates (async) |
left_click() |
() -> None |
Left click at current position (async) |
right_click() |
() -> None |
Right click at current position (async) |
middle_click() |
() -> None |
Middle click at current position (async) |
double_click() |
() -> None |
Double left click (async) |
triple_click() |
() -> None |
Triple left click (async) |
left_click_drag() |
(start_x, start_y, end_x, end_y) -> None |
Drag from start to end (async) |
cursor_position() |
() -> Tuple[int, int] |
Get current cursor (x, y) (async) |
| Method | Signature | Description |
|---|---|---|
type() |
(text: str) -> None |
Type text characters (async) |
key() |
(text: str) -> None |
Press key or key combination (async) |
The key() method uses xdotool key syntax:
| Key | Syntax |
|---|---|
| Enter | Return |
| Tab | Tab |
| Escape | Escape |
| Backspace | BackSpace |
| Delete | Delete |
| Arrow keys | Up, Down, Left, Right |
| Function keys | F1, F2, ... F12 |
| Modifiers | ctrl, alt, shift, super |
| Combinations | ctrl+c, ctrl+shift+s, alt+Tab |
Examples:
await computer.key("Return") # Press Enter
await computer.key("ctrl+c") # Copy
await computer.key("ctrl+shift+s") # Save As
await computer.key("alt+Tab") # Switch window
await computer.key("ctrl+a Delete") # Select all and delete| Method | Signature | Description |
|---|---|---|
wait_until_ready() |
(timeout: int = 60) -> None |
Wait for desktop ready (async) |
screenshot() |
() -> dict |
Capture screen (async) |
scroll() |
(x, y, direction, amount=3) -> None |
Scroll at position (async) |
get_screen_size() |
() -> Tuple[int, int] |
Get screen dimensions (async) |
{
"data": str, # Base64-encoded PNG
"width": int, # 1024 (default)
"height": int, # 768 (default)
"format": str # "png"
}| Direction | Description |
|---|---|
"up" |
Scroll up |
"down" |
Scroll down |
"left" |
Scroll left |
"right" |
Scroll right |
async with ComputerBox() as desktop:
await desktop.wait_until_ready()
# Take screenshot
screenshot = await desktop.screenshot()
# Mouse interaction
await desktop.mouse_move(100, 200)
await desktop.left_click()
# Type text
await desktop.type("Hello, World!")
await desktop.key("Return")
# Get screen size
width, height = await desktop.get_screen_size()Box for interactive terminal sessions with PTY support.
from boxlite import InteractiveBoxInteractiveBox(
image: str,
shell: str = "/bin/sh",
tty: bool = None,
memory_mib: int = None,
cpus: int = None,
runtime: Boxlite = None,
name: str = None,
auto_remove: bool = True,
**kwargs
)| Parameter | Type | Default | Description |
|---|---|---|---|
image |
str |
Required | Container image |
shell |
str |
"/bin/sh" |
Shell to run |
tty |
bool | None |
None |
TTY mode (see below) |
| Value | Behavior |
|---|---|
None |
Auto-detect from sys.stdin.isatty() |
True |
Force TTY mode with I/O forwarding |
False |
No I/O forwarding (programmatic control) |
| Method | Signature | Description |
|---|---|---|
wait() |
() -> None |
Wait for shell to exit (async) |
# Interactive shell session
async with InteractiveBox(image="alpine:latest") as box:
# You're now in an interactive shell
# Type commands, see output in real-time
# Type "exit" to close
await box.wait()Synchronous wrappers using greenlet fiber switching. Requires pip install boxlite[sync].
from boxlite import SyncBoxlite, SyncBox, SyncSimpleBox, SyncCodeBox| Use Case | API |
|---|---|
| New async applications | Async API (default) |
| Existing sync codebase | Sync API |
| Jupyter notebooks | Sync API |
| REPL/interactive use | Sync API |
| Inside async functions | Async API only |
| Async API | Sync API | Notes |
|---|---|---|
Boxlite |
SyncBoxlite |
get_info() and list_info() are async-only |
Box |
SyncBox |
Box.info() is async-only and is not exposed by SyncBox |
Execution |
SyncExecution |
|
ExecStdout |
SyncExecStdout |
Regular iterator |
ExecStderr |
SyncExecStderr |
Regular iterator |
SimpleBox |
SyncSimpleBox |
SimpleBox.info() is async-only and is not exposed by SyncSimpleBox |
CodeBox |
SyncCodeBox |
Inherits the async-only metadata rule |
from boxlite import SyncBoxlite, BoxOptions
with SyncBoxlite.default() as runtime:
box = runtime.create(BoxOptions(image="alpine:latest"))
execution = box.exec("echo", ["Hello"])
for line in execution.stdout():
print(line)
box.stop()from boxlite import SyncSimpleBox
with SyncSimpleBox(image="python:slim") as box:
result = box.exec("python", "-c", "print('Hello!')")
print(result.stdout)from boxlite import SyncCodeBox
with SyncCodeBox() as cb:
result = cb.run("print('Hello, World!')")
print(result)The sync API uses greenlet fiber switching:
- A dispatcher fiber runs the asyncio event loop
- User code runs in the main fiber
- Sync methods switch to dispatcher, await async operations, then switch back
Limitation: Cannot be used inside an async context (when an event loop is already running).
from boxlite import BoxliteError, ExecError, TimeoutError, ParseErrorBoxliteError (base)
├── ExecError # Command execution failed
├── TimeoutError # Operation timed out
└── ParseError # Output parsing failed
Base exception for all BoxLite errors.
try:
async with SimpleBox(image="invalid:image") as box:
pass
except BoxliteError as e:
print(f"BoxLite error: {e}")Raised when a command execution fails (non-zero exit code).
| Attribute | Type | Description |
|---|---|---|
command |
str |
The command that failed |
exit_code |
int |
Non-zero exit code |
stderr |
str |
Standard error output |
try:
result = await box.exec("false") # Exit code 1
except ExecError as e:
print(f"Command: {e.command}")
print(f"Exit code: {e.exit_code}")
print(f"Stderr: {e.stderr}")Raised when an operation times out.
try:
await computer.wait_until_ready(timeout=5)
except TimeoutError:
print("Desktop did not become ready in time")Raised when output parsing fails.
try:
x, y = await computer.cursor_position()
except ParseError:
print("Failed to parse cursor position")Aggregate metrics across all boxes.
| Field | Type | Description |
|---|---|---|
boxes_created |
int |
Total boxes created |
boxes_destroyed |
int |
Total boxes destroyed |
total_exec_calls |
int |
Total command executions |
active_boxes |
int |
Currently running boxes |
runtime = Boxlite.default()
metrics = await runtime.metrics()
print(f"Boxes created: {metrics.boxes_created}")
print(f"Active boxes: {metrics.active_boxes}")Per-box resource usage metrics.
| Field | Type | Description |
|---|---|---|
cpu_time_ms |
int |
Total CPU time in milliseconds |
memory_usage_bytes |
int |
Current memory usage in bytes |
network_bytes_sent |
int |
Total bytes sent |
network_bytes_received |
int |
Total bytes received |
metrics = await box.metrics()
print(f"CPU time: {metrics.cpu_time_ms}ms")
print(f"Memory: {metrics.memory_usage_bytes / (1024**2):.2f} MB")Default values used by BoxLite.
| Constant | Value | Description |
|---|---|---|
DEFAULT_CPUS |
1 |
Default CPU cores |
DEFAULT_MEMORY_MIB |
2048 |
Default memory in MiB |
COMPUTERBOX_CPUS |
2 |
ComputerBox default CPUs |
COMPUTERBOX_MEMORY_MIB |
2048 |
ComputerBox default memory |
COMPUTERBOX_DISPLAY_WIDTH |
1024 |
Screen width in pixels |
COMPUTERBOX_DISPLAY_HEIGHT |
768 |
Screen height in pixels |
COMPUTERBOX_GUI_HTTP_PORT |
3000 |
HTTP GUI port |
COMPUTERBOX_GUI_HTTPS_PORT |
3001 |
HTTPS GUI port |
DESKTOP_READY_TIMEOUT |
60 |
Desktop ready timeout (seconds) |
- Python SDK README - Quick start and examples
- Getting Started Guide - Installation
- Configuration Reference - BoxOptions details
- Error Codes - Error handling