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
| Constructor | Default kind | Local runtime |
|---|
Image.linux() | vm | QEMU |
Image.linux(kind='container') | container | Docker |
Image.macos() | vm | Lume (Apple Silicon) |
Image.windows() | vm | QEMU / Hyper-V |
Image.android() | vm | QEMU |
Constructor parameters
Image.linux
Image.macos
Image.windows
Image.android
Image.linux(distro='ubuntu', version='24.04', kind='vm')
| Parameter | Type | Default | Description |
|---|
distro | str | 'ubuntu' | Linux distribution name |
version | str | '24.04' | Distribution version string |
kind | str | 'vm' | 'vm' for QEMU, 'container' for Docker/XFCE |
Image.macos(version='26', kind='vm')
| Parameter | Type | Default | Description |
|---|
version | str | '26' | '26' / 'tahoe' (latest) or '15' / 'sequoia' |
kind | str | 'vm' | Always 'vm' (Apple Virtualization) |
Image.windows(version='11', kind='vm')
| Parameter | Type | Default | Description |
|---|
version | str | '11' | Windows version |
kind | str | 'vm' | Always 'vm' (QEMU or Hyper-V) |
Image.android(version='14', kind='vm')
| Parameter | Type | Default | Description |
|---|
version | str | '14' | Android version |
kind | str | 'vm' | Always 'vm' (QEMU emulator) |
Install packages
Use the package manager that matches the target OS. Each method accepts one or more package names and returns a new Image.
Linux
macOS
Windows
Android
# 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")
# Homebrew packages
Image.macos().brew_install("ffmpeg", "jq", "node")
# Python packages
Image.macos().pip_install("requests", "Pillow")
# Chocolatey packages
Image.windows().choco_install("nodejs", "git")
# winget packages
Image.windows().winget_install("Microsoft.VisualStudioCode")
# Python packages
Image.windows().pip_install("requests")
# Install an APK via adb
Image.android().apk_install("/path/to/app.apk")
# Build and install a PWA as a WebView APK
Image.android().pwa_install("https://example.com/manifest.json")
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']},
# ]
# }