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.

An Image is the immutable description of everything a sandbox should contain when it first starts: the operating system, packages, environment variables, copied files, and setup commands. It is not the running sandbox — it is the recipe used to produce one. Because each builder method returns a new Image rather than mutating the original, you can branch a single base image into multiple specializations without repeating setup work.

Choose a base image

Start with the constructor that matches the operating system and isolation level you need.
from cua import Image

Image.linux()                         # Ubuntu 24.04 VM (default, QEMU)
Image.linux(kind="container")         # Ubuntu 24.04 container (Docker / XFCE)
Image.linux("ubuntu", "22.04")        # Older Ubuntu VM
Image.macos()                         # macOS Tahoe (version "26", latest)
Image.macos("15")                     # macOS Sequoia
Image.windows()                       # Windows 11 VM
Image.android()                       # Android 14 VM
ConstructorDefault kindLocal runtime
Image.linux()vmQEMU
Image.linux(kind='container')containerDocker
Image.macos()vmLume (Apple Silicon)
Image.windows()vmQEMU / Hyper-V
Image.android()vmQEMU

Constructor parameters

Image.linux(distro='ubuntu', version='24.04', kind='vm')
ParameterTypeDefaultDescription
distrostr'ubuntu'Linux distribution name
versionstr'24.04'Distribution version string
kindstr'vm''vm' for QEMU, 'container' for Docker/XFCE

Install packages

Use the package manager that matches the target OS. Each method accepts one or more package names and returns a new Image.
# APT packages
Image.linux().apt_install("curl", "git", "ffmpeg")

# Python packages
Image.linux().pip_install("numpy", "pandas", "playwright")

# Python packages via uv (faster, installs into cua-server project)
Image.linux().uv_install("numpy", "pandas")

Set non-sensitive environment variables

Use .env() to set configuration values that are safe to store in the image spec.
Image.linux().env(
    LOG_LEVEL="info",
    APP_ENV="production",
    PORT="8080",
)
.env() values are stored in the Image spec in plaintext. Anyone who can inspect the image spec can read them. Do not use .env() for API keys, passwords, or tokens. See Secrets for the correct approach.

Run setup commands

Use .run() to execute arbitrary shell commands during image setup — for example, bootstrapping a Node.js environment or creating directories.
Image.linux().run("curl -fsSL https://deb.nodesource.com/setup_20.x | bash -")
Image.linux().run("mkdir -p /app/data && chmod 755 /app/data")

Copy files into the image

Use .copy() to embed local files (configs, scripts, data) into the image at a given path.
Image.linux().copy("./config.json", "/app/config.json")
Image.linux().copy("./entrypoint.sh", "/usr/local/bin/entrypoint.sh")
Only copy files that are safe to bake into the image. For secrets and credentials, inject them at runtime using sb.shell.run. See Secrets.

Expose ports

Mark the ports your workload will listen on. These are used by sb.tunnel.forward() to forward sandbox ports to localhost.
Image.linux().expose(8080).expose(5432)

Chain builder calls

Builder calls are composable — every method returns a new Image, so you can chain as many layers as needed. The original image is never modified.
img = (
    Image.linux()
    .apt_install("curl", "git", "ffmpeg")
    .pip_install("requests", "Pillow")
    .env(APP_ENV="production", PORT="8080")
    .run("mkdir -p /app/data")
    .copy("./config.json", "/app/config.json")
    .expose(8080)
)

Forking a base image

Because images are immutable, you can create a shared base and fork it for different purposes without duplicating setup:
base = Image.linux().apt_install("curl", "git")

dev  = base.pip_install("ipython", "rich").env(DEBUG="1")
prod = base.pip_install("gunicorn").run("useradd -m appuser")

Use a custom OCI registry image (BYOI)

Use Image.from_registry() when your base image already exists in a container registry. You can then chain builder calls on top of it.
# Pull from GitHub Container Registry
Image.from_registry("ghcr.io/trycua/macos-tahoe-cua:latest")

# Pull from Docker Hub
Image.from_registry("ubuntu:22.04")

# Chain builder calls on a registry image
img = Image.from_registry("ubuntu:22.04").apt_install("curl")

Use a local disk image

Use Image.from_file() for qcow2, vhdx, raw, or iso disk images. HTTP/HTTPS URLs are downloaded and cached automatically in ~/.cua/cua-sandbox/image-cache/.
Image.from_file("/path/to/disk.qcow2", os_type="linux")
Image.from_file("/path/to/windows.vhdx", os_type="windows")

# Download and cache automatically
Image.from_file("https://example.com/disk.qcow2", os_type="linux")

Inspect an image spec

Call .to_dict() to see the full image spec before launching a sandbox. This is useful for debugging layer ordering and verifying configuration.
img = Image.linux().apt_install("curl").pip_install("requests")
print(img.to_dict())
# {
#   'os_type': 'linux',
#   'distro': 'ubuntu',
#   'version': '24.04',
#   'kind': 'vm',
#   'layers': [
#     {'type': 'apt_install', 'packages': ['curl']},
#     {'type': 'pip_install', 'packages': ['requests']},
#   ]
# }

Build docs developers (and LLMs) love