Python SDK API Reference

May 2, 2026 · View on GitHub

Complete API reference for the BoxLite Python SDK.

Python: 3.10+ Platforms: macOS (Apple Silicon), Linux (x86_64, ARM64)

Table of Contents


Runtime Management

boxlite.Boxlite

The main runtime for creating and managing boxes.

from boxlite import Boxlite, Options, BoxOptions, ImageRegistry

Class Methods

MethodSignatureDescription
default()() -> BoxliteCreate runtime with default settings (~/.boxlite)
__init__()(options: Options) -> BoxliteCreate runtime with custom options

Instance Methods

MethodSignatureDescription
create()(options: BoxOptions, name: str = None) -> BoxCreate a new box (async)
get()(box_id: str) -> BoxReattach to an existing box by ID (async)
list()() -> List[BoxInfo]List all boxes (async)
metrics()() -> RuntimeMetricsGet runtime-wide metrics (async)

Example

# 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():
    print(f"{info.id}: {info.status}")

boxlite.Options

Runtime configuration options.

FieldTypeDefaultDescription
home_dirstr~/.boxliteBase directory for runtime data
image_registriesList[ImageRegistry][]Registry transport, TLS, search, and auth configuration

boxlite.ImageRegistry

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",
)
FieldTypeDefaultDescription
hoststrRequiredRegistry host, optionally with port. Do not include http:// or https://
transportstr"https""https" or "http"
skip_verifyboolFalseDisable TLS certificate and hostname verification for HTTPS registries
searchboolFalseInclude this host when resolving unqualified image references
username / passwordstr | NoneNoneBasic auth credentials. Provide both together
bearer_tokenstr | NoneNoneBearer token auth

boxlite.BoxOptions

Configuration options for creating a box.

FieldTypeDefaultDescription
imagestrRequiredOCI image URI (e.g., "python:slim", "alpine:latest")
cpusint1Number of CPU cores (1 to host CPU count)
memory_mibint512Memory limit in MiB (128-65536)
disk_size_gbint | NoneNonePersistent disk size in GB (None = ephemeral)
working_dirstr"/root"Working directory inside container
envList[Tuple[str, str]][]Environment variables as (key, value) pairs
volumesList[Tuple[str, str, str]][]Volume mounts as (host_path, guest_path, mode)
networkNetworkSpec | NoneNoneStructured network configuration. Omit for default enabled networking.
portsList[Tuple[int, int, str]][]Port forwarding as (host_port, guest_port, protocol)
secretsList[Secret][]Outbound HTTP(S) secret substitution rules
auto_removeboolTrueAuto cleanup when stopped
detachboolFalseSurvive parent process exit

NetworkSpec

from boxlite import NetworkSpec

network = NetworkSpec(
    mode="enabled",
    allow_net=["api.openai.com"],
)
FieldTypeDefaultDescription
modestrRequired"enabled" or "disabled"
allow_netList[str][]Outbound allowlist used only when mode="enabled"

mode="disabled" removes the guest network interface entirely.

Volume Mount Format

volumes=[
    ("/host/config", "/etc/app/config", "ro"),  # Read-only
    ("/host/data", "/mnt/data", "rw"),          # Read-write
]

Port Forwarding Format

ports=[
    (8080, 80, "tcp"),    # HTTP
    (5432, 5432, "tcp"),  # PostgreSQL
    (53, 53, "udp"),      # DNS
]

Secret Format

from boxlite import Secret

secrets=[
    Secret(
        name="openai",
        value="sk-...",
        hosts=["api.openai.com"],
        # placeholder defaults to "<BOXLITE_SECRET:openai>"
    )
]

Box Handle

boxlite.Box

Handle to a running or stopped box.

Properties

PropertyTypeDescription
idstrUnique box identifier (ULID format)

Methods

MethodSignatureDescription
exec()(cmd, args, env, tty) -> ExecutionExecute command (async)
stop()() -> NoneStop the box gracefully (async)
remove()() -> NoneDelete box and its data (async)
info()() -> BoxInfoGet box metadata (async)
metrics()() -> BoxMetricsGet resource usage metrics (async)

boxlite.BoxInfo

Metadata about a box.

FieldTypeDescription
idstrUnique box identifier (ULID)
namestr | NoneOptional user-assigned name
statusstrCurrent status: "running", "stopped", "created"
created_atdatetimeCreation timestamp
pidint | NoneProcess ID (if running)
imagestrOCI image used
cpusintAllocated CPU cores
memory_mibintAllocated memory in MiB

boxlite.BoxStateInfo

Detailed state information for a box.

ValueDescription
CreatedBox created but not yet started
StartingBox is initializing
RunningBox is running and ready
StoppingBox is shutting down
StoppedBox is stopped
FailedBox encountered an error

Command Execution

boxlite.Execution

Represents a running command execution.

Methods

MethodSignatureDescription
stdout()() -> ExecStdoutGet stdout stream (async iterator)
stderr()() -> ExecStderrGet stderr stream (async iterator)
stdin()() -> ExecStdinGet stdin writer
wait()() -> ExecResultWait for completion (async)
kill()(signal: int = 9) -> NoneSend signal to process (async)
resize_tty()(rows: int, cols: int) -> NoneResize PTY terminal for executions started with tty=True (async)

Example

# 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}")

boxlite.ExecStdout / boxlite.ExecStderr

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.


boxlite.ExecStdin

Writer for sending input to a running process.

Methods

MethodSignatureDescription
send_input()(data: bytes) -> NoneWrite bytes to stdin (async)

Example

# 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()

boxlite.ExecResult

Result of a completed execution.

FieldTypeDescription
exit_codeintProcess exit code (0 = success)

Note: For higher-level APIs (SimpleBox.exec()), the result also includes stdout and stderr strings.


Box Types

boxlite.SimpleBox

Context manager for basic command execution with automatic cleanup.

from boxlite import SimpleBox

Constructor

SimpleBox(
    image: str,
    memory_mib: int = None,
    cpus: int = None,
    runtime: Boxlite = None,
    name: str = None,
    auto_remove: bool = True,
    **kwargs
)
ParameterTypeDefaultDescription
imagestrRequiredContainer image to use
memory_mibintSystem defaultMemory limit in MiB
cpusintSystem defaultNumber of CPU cores
runtimeBoxliteGlobal defaultRuntime instance
namestrNoneOptional unique name
auto_removeboolTrueRemove box when stopped
**kwargsAdditional options: env, volumes, ports, working_dir, network, secrets

Properties

PropertyTypeDescription
idstrBox ID (raises if not started)

Methods

MethodSignatureDescription
start()() -> SelfExplicitly start the box (async)
exec()(cmd, *args, env=None, user=None, timeout=None, cwd=None) -> ExecResultExecute command and wait (async)
info()() -> BoxInfoGet box metadata
shutdown()() -> NoneShutdown and release resources

Example

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 seconds

boxlite.CodeBox

Specialized box for Python code execution with package management.

from boxlite import CodeBox

Constructor

CodeBox(
    image: str = "python:slim",
    memory_mib: int = None,
    cpus: int = None,
    runtime: Boxlite = None,
    **kwargs
)

Methods

MethodSignatureDescription
run()(code: str, timeout: int = None) -> strExecute Python code (async)
run_script()(script_path: str) -> strExecute Python script file (async)
install_package()(package: str) -> strInstall package with pip (async)
install_packages()(*packages: str) -> strInstall multiple packages (async)

Example

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)

boxlite.BrowserBox

Box configured for browser automation with Chrome DevTools Protocol.

from boxlite import BrowserBox, BrowserBoxOptions

BrowserBoxOptions

FieldTypeDefaultDescription
browserstr"chromium"Browser type: "chromium", "firefox", "webkit"
memoryint2048Memory in MiB
cpuint2Number of CPU cores

Browser CDP Ports

BrowserPort
chromium9222
firefox9223
webkit9224

Methods

MethodSignatureDescription
endpoint()() -> strGet CDP endpoint URL

Example

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 })

boxlite.ComputerBox

Box with full desktop environment and GUI automation capabilities.

from boxlite import ComputerBox

Constructor

ComputerBox(
    cpu: int = 2,
    memory: int = 2048,
    gui_http_port: int = 3000,
    gui_https_port: int = 3001,
    runtime: Boxlite = None,
    **kwargs
)

Mouse Methods

MethodSignatureDescription
mouse_move()(x: int, y: int) -> NoneMove cursor to coordinates (async)
left_click()() -> NoneLeft click at current position (async)
right_click()() -> NoneRight click at current position (async)
middle_click()() -> NoneMiddle click at current position (async)
double_click()() -> NoneDouble left click (async)
triple_click()() -> NoneTriple left click (async)
left_click_drag()(start_x, start_y, end_x, end_y) -> NoneDrag from start to end (async)
cursor_position()() -> Tuple[int, int]Get current cursor (x, y) (async)

Keyboard Methods

MethodSignatureDescription
type()(text: str) -> NoneType text characters (async)
key()(text: str) -> NonePress key or key combination (async)
Key Syntax Reference

The key() method uses xdotool key syntax:

KeySyntax
EnterReturn
TabTab
EscapeEscape
BackspaceBackSpace
DeleteDelete
Arrow keysUp, Down, Left, Right
Function keysF1, F2, ... F12
Modifiersctrl, alt, shift, super
Combinationsctrl+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

Display Methods

MethodSignatureDescription
wait_until_ready()(timeout: int = 60) -> NoneWait for desktop ready (async)
screenshot()() -> dictCapture screen (async)
scroll()(x, y, direction, amount=3) -> NoneScroll at position (async)
get_screen_size()() -> Tuple[int, int]Get screen dimensions (async)
Screenshot Return Format
{
    "data": str,    # Base64-encoded PNG
    "width": int,   # 1024 (default)
    "height": int,  # 768 (default)
    "format": str   # "png"
}
Scroll Directions
DirectionDescription
"up"Scroll up
"down"Scroll down
"left"Scroll left
"right"Scroll right

Example

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()

boxlite.InteractiveBox

Box for interactive terminal sessions with PTY support.

from boxlite import InteractiveBox

Constructor

InteractiveBox(
    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
)
ParameterTypeDefaultDescription
imagestrRequiredContainer image
shellstr"/bin/sh"Shell to run
ttybool | NoneNoneTTY mode (see below)
TTY Mode
ValueBehavior
NoneAuto-detect from sys.stdin.isatty()
TrueForce TTY mode with I/O forwarding
FalseNo I/O forwarding (programmatic control)

Methods

MethodSignatureDescription
wait()() -> NoneWait for shell to exit (async)

Example

# 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()

Sync API

Synchronous wrappers using greenlet fiber switching. Requires pip install boxlite[sync].

from boxlite import SyncBoxlite, SyncBox, SyncSimpleBox, SyncCodeBox

When to Use

Use CaseAPI
New async applicationsAsync API (default)
Existing sync codebaseSync API
Jupyter notebooksSync API
REPL/interactive useSync API
Inside async functionsAsync API only

Comparison Table

Async APISync APINotes
BoxliteSyncBoxlite
BoxSyncBox
ExecutionSyncExecution
ExecStdoutSyncExecStdoutRegular iterator
ExecStderrSyncExecStderrRegular iterator
SimpleBoxSyncSimpleBox
CodeBoxSyncCodeBox

Classes

SyncBoxlite

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()

SyncSimpleBox

from boxlite import SyncSimpleBox

with SyncSimpleBox(image="python:slim") as box:
    result = box.exec("python", "-c", "print('Hello!')")
    print(result.stdout)

SyncCodeBox

from boxlite import SyncCodeBox

with SyncCodeBox() as cb:
    result = cb.run("print('Hello, World!')")
    print(result)

Architecture

The sync API uses greenlet fiber switching:

  1. A dispatcher fiber runs the asyncio event loop
  2. User code runs in the main fiber
  3. 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).


Error Types

from boxlite import BoxliteError, ExecError, TimeoutError, ParseError

Exception Hierarchy

BoxliteError (base)
├── ExecError       # Command execution failed
├── TimeoutError    # Operation timed out
└── ParseError      # Output parsing failed

BoxliteError

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}")

ExecError

Raised when a command execution fails (non-zero exit code).

AttributeTypeDescription
commandstrThe command that failed
exit_codeintNon-zero exit code
stderrstrStandard 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}")

TimeoutError

Raised when an operation times out.

try:
    await computer.wait_until_ready(timeout=5)
except TimeoutError:
    print("Desktop did not become ready in time")

ParseError

Raised when output parsing fails.

try:
    x, y = await computer.cursor_position()
except ParseError:
    print("Failed to parse cursor position")

Metrics

boxlite.RuntimeMetrics

Aggregate metrics across all boxes.

FieldTypeDescription
boxes_createdintTotal boxes created
boxes_destroyedintTotal boxes destroyed
total_exec_callsintTotal command executions
active_boxesintCurrently running boxes
runtime = Boxlite.default()
metrics = await runtime.metrics()

print(f"Boxes created: {metrics.boxes_created}")
print(f"Active boxes: {metrics.active_boxes}")

boxlite.BoxMetrics

Per-box resource usage metrics.

FieldTypeDescription
cpu_time_msintTotal CPU time in milliseconds
memory_usage_bytesintCurrent memory usage in bytes
network_bytes_sentintTotal bytes sent
network_bytes_receivedintTotal 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")

Constants

Default values used by BoxLite.

ConstantValueDescription
DEFAULT_CPUS1Default CPU cores
DEFAULT_MEMORY_MIB2048Default memory in MiB
COMPUTERBOX_CPUS2ComputerBox default CPUs
COMPUTERBOX_MEMORY_MIB2048ComputerBox default memory
COMPUTERBOX_DISPLAY_WIDTH1024Screen width in pixels
COMPUTERBOX_DISPLAY_HEIGHT768Screen height in pixels
COMPUTERBOX_GUI_HTTP_PORT3000HTTP GUI port
COMPUTERBOX_GUI_HTTPS_PORT3001HTTPS GUI port
DESKTOP_READY_TIMEOUT60Desktop ready timeout (seconds)

See Also