Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/trycua/cua/llms.txt

Use this file to discover all available pages before exploring further.

A Cua Sandbox is a full, isolated computer, not a remote desktop session. Inside that one machine, an agent can run code through shell commands or Python, and it can also drive the graphical interface through screenshots, the accessibility tree, clicks, and typing. Both halves share one filesystem, one set of processes, and one OS state — that is what makes a sandbox more than a cloud VM or a container.

Sandboxes and real machines

Cua Driver operates a real machine you already have. Its actions happen in the same desktop environment you use, which means they can affect your local files and running apps. A sandbox is different. It is a disposable machine created for a task. It starts from a known state, accumulates state only while it lives, and can be deleted without consequence. Actions inside a sandbox affect only that sandbox — they do not move the host mouse, change host files, or touch other sandboxes. This isolation is what makes sandboxes suitable for repeatable agent work. The agent gets a whole computer, but the effects stay contained.

The code half and the GUI half

Every sandbox exposes two complementary interfaces to the same machine. The code half is how an agent runs programs inside the sandbox:
  • shell.run(cmd) — run a shell command and return stdout/stderr
  • computer.pty / cua do shell — interactive PTY or terminal session
  • venv_install, venv_exec, @sandboxed decorator — run Python code inside the sandbox’s own virtualenv
The GUI half is how an agent uses the sandbox like a desktop:
  • screenshot() — capture the current screen
  • Accessibility tree inspection — read semantic UI structure from the OS
  • mouse.click(x, y), mouse.double_click(x, y), mouse.scroll(...) — pointer events
  • keyboard.type(text), keyboard.press(key) — key events
  • mobile.gesture(start, end) — multi-touch gestures (Android)
Because both halves share the same filesystem and OS state, you can mix them freely:
# Set up state in code, then automate the UI over it
result = await sb.shell.run("echo 'hello' > /tmp/test.txt")
await sb.keyboard.type("cat /tmp/test.txt")
await sb.keyboard.press("Return")
screenshot = await sb.screenshot()

Runtime backends

Cua Sandbox supports multiple runtime backends depending on the target OS and isolation requirements.

Linux containers

A Linux container sandbox starts quickly because it shares the host kernel. It layers a Linux userspace, a desktop environment (XFCE), and a remote display stack (KasmWeb). Startup is fast, but it is not identical to a physical Linux box — kernel behavior, device access, and isolation come from the container host. Use when: Fast startup is more important than full OS fidelity. Good for CI, testing, and most Linux automation tasks.

Full VMs (QEMU)

A full VM emulates hardware and boots its own kernel. Linux VMs, Windows VMs, and Android VMs use QEMU. Full VMs are slower to start than containers, but provide complete OS fidelity because the guest OS owns its kernel and hardware model. Use when: The task depends on specific kernel behavior, device drivers, or OS-level state that a container cannot faithfully reproduce.

Lume VMs (macOS)

macOS sandboxes on Apple Silicon use Lume, which wraps Apple’s Virtualization.framework. This provides near-native performance for macOS guests on Apple Silicon hardware. Use when: The task requires a real macOS environment — for example, testing a macOS app, using macOS-specific APIs, or automating GUI workflows in native macOS applications.

Runtime selection summary

TargetImage callBackendStartup speed
Linux containerImage.linux(kind="container")DockerFast
Linux VMImage.linux(kind="vm")QEMUModerate
macOS VMImage.macos()LumeModerate
Windows VMImage.windows()QEMU / Hyper-VModerate
Android VMImage.android()QEMUModerate

Images as starting-state contracts

An Image is the immutable description of the sandbox’s starting environment. It is not the running sandbox itself. An Image defines:
  • The OS type, distribution, and version
  • Packages to install (apt_install, pip_install)
  • Environment variables (env)
  • Files to copy in (copy)
  • Setup commands to run (run)
The image builder composes these layers. They are applied once at launch to produce the sandbox’s initial state. Installing another package later changes that sandbox, not the Image.
from cua import Image

# Built-in images
img = Image.linux(kind="container")
img = Image.macos()
img = Image.windows()

# Custom image built from a base
img = (
    Image.linux(kind="container")
    .apt_install(["git", "curl", "python3-pip"])
    .pip_install(["requests", "beautifulsoup4"])
    .run("useradd -m myuser")
    .env({"MY_VAR": "hello"})
)
The Image describes what a fresh sandbox should look like. The sandbox is the live machine created from that description. This separation makes environments reproducible.

Lifecycle patterns

Sandbox lifetime is independent of agent connection lifetime. Ephemeral sandboxes exist for one block of work and are destroyed when the async with block exits. No cleanup needed.
async with Sandbox.ephemeral(Image.linux(kind="container"), local=True) as sb:
    await sb.shell.run("echo hello")
# Sandbox is destroyed here
Persistent sandboxes survive process exits. They are created once, identified by name, and reconnected to later.
# Create once
await Sandbox.create("my-project", Image.linux(kind="container"), local=True)

# Reconnect in a later process
async with Sandbox.connect("my-project") as sb:
    await sb.shell.run("ls /my-project")
Connect mode attaches to an already-running sandbox without creating or deleting it. Disconnecting drops the control connection; deleting destroys the machine and its state. Those are different operations.

Snapshots and forks

A snapshot captures the disk state of a running sandbox and returns a new Image. That Image can start any number of fresh sandboxes from the captured point. Snapshots are useful when setup is expensive. Install packages, download models, or prepare data once — then fork as many fresh sandboxes from that snapshot as you need, without repeating the setup. A fork starts from the same snapshot but gets its own writable disk. Changes in one fork do not affect the snapshot or sibling forks. On copy-on-write storage, forks can be near-instant because unchanged blocks are shared until a sandbox writes to them.

Local execution

Local mode runs the sandbox on your own hardware. Select it with local=True:
async with Sandbox.ephemeral(Image.linux(kind="container"), local=True) as sb:
    ...
Local mode uses:
  • Docker Desktop or Docker Engine for Linux containers
  • Lume for macOS VMs on Apple Silicon
  • QEMU or Hyper-V for other VM backends
Performance depends on your machine’s available CPU, memory, disk, and virtualization support. Cloud mode (the default, without local=True) runs on Cua’s managed infrastructure at cua.ai.

The computer-server

Inside every sandbox, a lightweight computer-server process accepts connections from the Cua SDK and translates them into local OS calls — mouse events, keyboard events, screenshot captures, clipboard reads, and shell executions. This server is what makes the sandbox addressable as a remote computer from Python, regardless of the underlying runtime backend.

Further reading

First Sandbox tutorial

Create an ephemeral Linux sandbox and run your first shell command and screenshot.

First Lume VM tutorial

Set up a full macOS VM on Apple Silicon with Lume.

Sandbox lifecycle

Create, connect, snapshot, fork, and delete sandboxes.

Sandbox SDK reference

Complete API reference for all sandbox methods and types.

Build docs developers (and LLMs) love