Runtimes
Local runtimes (Docker, QEMU, Lume, Hyper-V, Tart, Android emulator) and local support checks.
Local runtimes (Docker, QEMU, Lume, Hyper-V, Tart, Android emulator) and local support checks.
Local sandboxes run on a runtime the SDK picks for the image. Pass one explicitly to Sandbox.create(..., runtime=...) to override it.
class RuntimeSupport
RuntimeSupport(
supported: bool,
hw_accel: bool,
runtime_installed: bool,
auto_installable: bool,
runtime_name: str,
host_os: str,
host_arch: str,
guest_os: str,
reason: str,
)Result of a local runtime compatibility check for a given Image.
| Attribute | Type | Description |
|---|---|---|
supported | bool | |
hw_accel | bool | |
runtime_installed | bool | |
auto_installable | bool | |
runtime_name | str | |
host_os | str | |
host_arch | str | |
guest_os | str | |
reason | str |
def check_local_support(image: 'Image') -> RuntimeSupportReturn a RuntimeSupport describing whether image can run locally.
| Parameter | Type | Default | Description |
|---|---|---|---|
image | 'Image' | required | The Image to check. Use Image.linux(), Image.macos(), etc. |
Returns: RuntimeSupport with .supported, .hw_accel, .reason, and more.
def skip_if_unsupported(image: 'Image', *, require_hw_accel: bool = False) -> NoneCall at the top of a pytest test/fixture to skip when the host can't run image.
Example:
async def test_macos_brew_install():
skip_if_unsupported(Image.macos())
async with Sandbox.ephemeral(Image.macos().brew_install("wget"), local=True) as sb:
assert (await sb.shell.run("wget --version")).success| Parameter | Type | Default | Description |
|---|---|---|---|
image | 'Image' | required | The Image the test intends to boot with local=True. |
require_hw_accel | bool | False | If True, also skip when hardware acceleration is unavailable (e.g. skip Android tests that would run in software emulation). |
class Runtime(ABC)Base class for local runtimes that create VMs/containers from an Image.
async def start(image: Image, name: str, **opts) -> RuntimeInfoStart a VM/container and return connection info.
async def stop(name: str) -> NoneStop and clean up a VM/container.
async def is_ready(info: RuntimeInfo, timeout: float = 120) -> boolWait until the sandbox is ready.
Daemon-agnostic: "ready" is the runtime's own notion (instance running, plus any probe the caller declared), never a specific guest agent.
async def suspend(name: str) -> NoneSuspend (pause/save state of) a running VM.
async def resume(image: 'Image', name: str, **opts) -> RuntimeInfoResume a suspended VM and return its RuntimeInfo.
async def list() -> list[dict]List known VMs managed by this runtime.
Returns a list of dicts with at minimum: name, status.
async def ensure_base(image: 'Image', base_name: str) -> CheckpointInfoPull/build image into a stopped base sandbox if not already present.
Idempotent. First call does the full pull; subsequent calls return immediately. The base sandbox is never started: it only serves as a fork source for ephemeral VMs.
async def fork(base_name: str, new_name: str, **opts) -> NoneCreate a new sandbox from a base/checkpoint using CoW where possible.
async def checkpoint(name: str, checkpoint_name: str, **opts) -> CheckpointInfoCapture the current state of a running sandbox as a named checkpoint.
async def list_checkpoints() -> list[CheckpointInfo]async def delete_checkpoint(checkpoint_name: str) -> Noneclass RuntimeInfo
RuntimeInfo(
host: str,
api_port: int,
vnc_port: Optional[int] = None,
api_key: Optional[str] = None,
container_id: Optional[str] = None,
name: Optional[str] = None,
qmp_port: Optional[int] = None,
environment: Optional[str] = None,
agent_type: Optional[str] = None,
guest_server_port: int = 3211,
exposed_ports: Optional[dict] = None,
ssh_port: Optional[int] = None,
ssh_username: Optional[str] = None,
ssh_password: Optional[str] = None,
ssh_key_filename: Optional[str] = None,
vnc_host: Optional[str] = None,
vnc_password: Optional[str] = None,
grpc_port: Optional[int] = None,
native: Any = None,
env_ready_timeout: Optional[float] = None,
env_token: Optional[str] = None,
)Connection info returned after a runtime spins up.
| Attribute | Type | Description |
|---|---|---|
host | str | |
api_port | int | |
vnc_port | Optional[int] | |
api_key | Optional[str] | |
container_id | Optional[str] | |
name | Optional[str] | |
qmp_port | Optional[int] | |
environment | Optional[str] | |
agent_type | Optional[str] | |
guest_server_port | int | |
exposed_ports | Optional[dict] | |
ssh_port | Optional[int] | |
ssh_username | Optional[str] | |
ssh_password | Optional[str] | |
ssh_key_filename | Optional[str] | |
vnc_host | Optional[str] | |
vnc_password | Optional[str] | |
grpc_port | Optional[int] | |
native | Any | |
env_ready_timeout | Optional[float] | |
env_token | Optional[str] |
class DockerRuntime(NativeRuntime)
DockerRuntime(
*,
api_port: int = DEFAULT_API_PORT,
vnc_port: int = DEFAULT_VNC_PORT,
ephemeral: bool = True,
volumes: Optional[list[str]] = None,
environment: Optional[dict[str, str]] = None,
devices: Optional[list[str]] = None,
platform: Optional[str] = None,
privileged: bool = False,
stop_timeout: int = 120,
cpus: Optional[int] = None,
memory_mb: Optional[int] = None,
server_port: Optional[int] = None,
)Runs OCI container images through the SDK's container backend.
api_port/vnc_port are accepted for compatibility; the SDK picks
free host ports and Sandbox.exposed_ports reports them.
volumes, devices, platform and privileged are not
supported by the sandboxed (gVisor) backend and are rejected.
| Attribute | Type | Description |
|---|---|---|
runtime_type | str | |
env_ready_timeout | float | |
delivers_guest_env | bool | |
api_port | int | |
vnc_port | int | |
stop_timeout | int |
async def start(image: Image, name: str, **opts) -> RuntimeInfodef QEMURuntime(mode: str = 'docker', **kwargs) -> RuntimeFactory that returns the appropriate QEMU runtime.
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | str | 'docker' | "docker" (default), "bare-metal", or "wsl2" |
class QEMUDockerRuntime(NativeQEMURuntime)
QEMUDockerRuntime(
*,
api_port: int = DEFAULT_API_PORT,
vnc_port: int = QEMU_VNC_PORT,
ephemeral: bool = True,
storage_dir: Optional[str | Path] = None,
memory_mb: int = 8192,
cpu_count: int = 4,
)QEMURuntime(mode="docker"): kept for compatibility.
The trycua/cua-qemu-* wrapper images drove their guest through
computer-server, which is gone; Linux and Windows guests now boot on the
SDK's QEMU backend (the SDK provisions QEMU itself). Android guests use
cua_sandbox.runtime.AndroidEmulatorRuntime or bare-metal QEMU.
| Attribute | Type | Description |
|---|---|---|
api_port | int | |
vnc_port | int |
async def start(image: Image, name: str, **opts) -> RuntimeInfoclass QEMUBaremetalRuntime(Runtime)
QEMUBaremetalRuntime(
*,
api_port: int = DEFAULT_API_PORT,
vnc_display: int = 0,
memory_mb: int = 4096,
cpu_count: int = 2,
arch: str = 'x86_64',
qmp_port: int = 4444,
use_qmp_transport: bool = False,
extra_args: Optional[list[str]] = None,
use_sdk: Optional[bool] = None,
)Bare-metal QEMU: launches qemu-system-* directly on the host.
Requires: - qemu-system-x86_64 (or qemu-system-aarch64) on PATH
use_sdk=False keeps the legacy in-process launcher, which boots
the given disk in place (the image builder needs that: the SDK always
puts an instance overlay on top of the disk).
| Attribute | Type | Description |
|---|---|---|
api_port | int | |
vnc_display | int | |
memory_mb | int | |
cpu_count | int | |
arch | str | |
qmp_port | int | |
use_qmp_transport | bool | |
extra_args | Optional[list[str]] | |
use_sdk | Optional[bool] |
async def start(image: Image, name: str, **opts) -> RuntimeInfoasync def stop(name: str) -> Noneasync def is_ready(info: RuntimeInfo, timeout: float = 120) -> boolasync def suspend(name: str) -> NoneSave VM state via QMP savevm then quit QEMU.
async def resume(image: 'Image', name: str, **opts) -> RuntimeInfoRelaunch QEMU with -loadvm to restore saved state.
async def list() -> list[dict]List known bare-metal QEMU sandboxes from state files, checking if alive.
class QEMUWSL2Runtime(Runtime)
QEMUWSL2Runtime(
*,
api_port: int = DEFAULT_API_PORT,
vnc_display: int = 0,
memory_mb: int = 4096,
cpu_count: int = 4,
arch: str = 'x86_64',
extra_args: Optional[list[str]] = None,
)QEMU via WSL2 with KVM hardware acceleration.
Runs qemu-system-x86_64 inside WSL2 where /dev/kvm is available, while keeping disk images on the Windows filesystem. Windows paths are automatically converted to /mnt/c/... paths for WSL access.
This is the fastest way to run QEMU on Windows: native KVM speeds vs TCG software emulation (bare-metal Windows) or Hyper-V (needs admin).
| Attribute | Type | Description |
|---|---|---|
api_port | int | |
vnc_display | int | |
memory_mb | int | |
cpu_count | int | |
arch | str | |
extra_args | Optional[list[str]] |
@staticmethod
def available() -> boolCheck if WSL2 + QEMU + KVM are available.
async def start(image: Image, name: str, **opts) -> RuntimeInfoasync def stop(name: str) -> Noneasync def is_ready(info: RuntimeInfo, timeout: float = 120) -> boolclass LumeRuntime(NativeRuntime)
LumeRuntime(
*,
lume_host: str = 'localhost',
lume_port: int = LUME_PROVIDER_PORT,
api_port: int = LUME_API_PORT,
ephemeral: bool = True,
cpus: Optional[int] = None,
memory_mb: Optional[int] = None,
)Runs macOS VMs via Lume, through the cua SDK.
| Attribute | Type | Description |
|---|---|---|
runtime_type | str | |
env_ready_timeout | float | |
lume_host | str | |
lume_port | int | |
api_port | int |
async def start(image: Image, name: str, **opts) -> RuntimeInfoasync def ensure_base(image: Image, base_name: str)Pull an OCI image into a stopped golden base VM, if it doesn't exist yet.
Idempotent: if base_name already exists and is stopped, returns immediately. Raises if the base VM is running, because cloning a live VM can produce dirty or inconsistent clones (same constraint as cloud snapshots). The base VM is never started; it only serves as a fork source.
async def fork(base_name: str, new_name: str, **opts) -> NoneClone a stopped VM base_name → new_name via APFS clonefile (instant).
The source VM must be stopped before calling this: cloning a running VM risks dirty state or clone failures (mirrors cloud snapshot behaviour).
async def checkpoint(name: str, checkpoint_name: str, **opts)Stop name, clone it into a checkpoint, then restart name.
Mirrors the cloud behaviour (stop → snapshot → restart) so clones are always taken from a clean stopped state.
async def list_checkpoints()Return VMs that are checkpoints (cua-base-* or cua-ckpt-* prefix).
async def delete_checkpoint(checkpoint_name: str) -> NoneDelete a checkpoint VM. Only operates on cua-base-* / cua-ckpt-* names.
async def list() -> list[dict]List all Lume VMs.
class HyperVRuntime(Runtime)
HyperVRuntime(
*,
api_port: int = DEFAULT_API_PORT,
switch_name: str = 'Default Switch',
memory_mb: int = 4096,
cpu_count: int = 4,
disk_size_gb: int = 64,
cache_dir: Optional[Path] = None,
windows_iso: Optional[str] = None,
product_key: Optional[str] = None,
)Runs Windows VMs via Hyper-V with layered VHDX caching.
On first use, builds a base Windows image from ISO using unattended install (same Autounattend.xml as the QEMU builder). The base image includes CUA computer-server pre-installed. This is cached and reused.
Each sandbox session gets its own ephemeral differencing disk on top.
| Attribute | Type | Description |
|---|---|---|
api_port | int | |
switch_name | str | |
memory_mb | int | |
cpu_count | int | |
disk_size_gb | int | |
cache_dir | Optional[Path] | |
windows_iso | Optional[str] | |
product_key | Optional[str] |
async def start(image: Image, name: str, **opts) -> RuntimeInfoasync def stop(name: str) -> NoneStop the VM, remove it, and delete the ephemeral session disk.
async def is_ready(info: RuntimeInfo, timeout: float = 120) -> boolDaemon-agnostic readiness: the VM is running and has an address.
start() already waited for the guest IP; the guest agent port is
a real TCP endpoint on the Hyper-V switch, so wait until it accepts a
connection (any daemon listening there), bounded by timeout.
class TartRuntime(Runtime)
TartRuntime(
*,
ephemeral: bool = True,
cpu_count: Optional[int] = None,
memory_mb: Optional[int] = None,
disk_gb: Optional[int] = None,
display: str = '1024x768',
ssh_username: str = TART_DEFAULT_USERNAME,
ssh_password: str = TART_DEFAULT_PASSWORD,
)Apple Virtualization.framework runtime via Tart CLI.
Uses VNC (host-side, random port) for screenshots and SSH for shell commands.
| Attribute | Type | Description |
|---|---|---|
ephemeral | bool | |
cpu_count | Optional[int] | |
memory_mb | Optional[int] | |
disk_gb | Optional[int] | |
display | str | |
ssh_username | str | |
ssh_password | str | |
vnc_host | Optional[str] | |
vnc_port | Optional[int] | |
vnc_password | Optional[str] |
async def start(image: Image, name: str, **opts) -> RuntimeInfoasync def is_ready(info: RuntimeInfo, timeout: float = 120) -> boolWait until SSH is reachable.
async def stop(name: str) -> Noneclass AndroidEmulatorRuntime(Runtime)
AndroidEmulatorRuntime(
*,
api_level: int = 34,
img_type: str = 'google_apis',
device_id: str = 'pixel',
memory_mb: int = 4096,
cpu_count: int = 4,
adb_port: Optional[int] = None,
no_boot_anim: bool = True,
gpu_mode: str = 'swiftshader_indirect',
headless: bool = True,
grpc_port: Optional[int] = None,
)Android emulator runtime using the official Android SDK.
Creates an AVD and launches the Android emulator, following the docker-android pattern. Uses ADB for boot detection, APK install, and shell commands.
| Attribute | Type | Description |
|---|---|---|
api_level | int | |
img_type | str | |
device_id | str | |
memory_mb | int | |
cpu_count | int | |
adb_port | Optional[int] | |
no_boot_anim | bool | |
gpu_mode | str | |
headless | bool | |
grpc_port | Optional[int] |
async def start(image: Image, name: str, **opts) -> RuntimeInfoasync def is_ready(info: RuntimeInfo, timeout: float = 300) -> boolWait for sys.boot_completed == 1 via ADB, like docker-android.
async def list() -> list[dict]List known Android emulator sandboxes from state files, checking if alive.
async def stop(name: str) -> Noneasync def take_screenshot() -> bytesTake a screenshot via ADB screencap.