Cua Docs

Sandbox SDK reference

Packages, configuration, and Sandbox lifecycle APIs for Python and TypeScript.

The Python Sandbox SDK supports local execution and hosted Fleet pools through one API. Backend support differs even when method names are shared. Use Sandbox runtime support for local/Fleet image and transport differences, and Sandbox lifecycle for connection, claim, and capacity ownership.

Packages#

This reference describes the published cua-sandbox 0.7.0 Python package and @trycua/fleet 0.1.2 TypeScript package.

DistributionImportRequirementAPI
cua-sandbox 0.7.0cua_sandboxPython >=3.11,<3.14Sandbox, Image, Pool, Template, and interfaces
cua 0.1.6cuaPython >=3.12,<3.14Umbrella package; reexports Sandbox and Image, but not Pool
@trycua/fleet 0.1.2@trycua/fleet/node or @trycua/fleet/browserEnvironment-specific WebAssembly entry pointFleet client, resource types, and builders

The Python Sandbox distribution can be installed independently:

pip install cua-sandbox==0.7.0

Its primary imports are:

from cua_sandbox import Image, Pool, Sandbox, Template

See Pool and claim reference, Image reference, OS and image catalog, Sandbox interfaces, and TypeScript Fleet reference.

Configuration and authentication#

configure() updates process-wide settings. All parameters are optional, keyword-only strings; None leaves a setting unchanged.

def configure(
    *, api_key=None, base_url=None, fleet_base_url=None, token_url=None,
    client_id=None, client_secret=None, fleet_token=None,
) -> None: ...

Fleet authentication uses a configured fleet_token, then FLEETS_TOKEN. If neither supplies a nonempty token, it uses client_id and client_secret from configure(), falling back to CUA_CLIENT_ID and CUA_CLIENT_SECRET.

Environment variablePurposeDefault
FLEETS_TOKENFleet bearer token; takes precedence over OAuth client credentialsNone
CUA_CLIENT_ID, CUA_CLIENT_SECRETFleet OAuth client credentialsNone
CUA_TOKEN_URLOAuth token endpointhttps://auth.cua.ai/realms/cyclops-cs/protocol/openid-connect/token
CUA_FLEET_BASE_URLFleet API endpointhttps://run.cua.ai
CUA_API_KEYLegacy VM API keyNone
CUA_BASE_URLLegacy VM API endpointhttps://api.cua.ai

Endpoint environment variables override the corresponding configure() values. Legacy API keys resolve from the per-call api_key, global configuration, ~/.cua/credentials, then CUA_API_KEY.

Credential acquisition is documented in Fleet pools need their own credentials. login(base_url=None) and whoami(api_key=None) belong to the legacy API-key flow; they do not configure Fleet OAuth credentials.

Sandbox creation#

Sandbox.create() returns a connected Sandbox. Sandbox.ephemeral() is an async context manager that performs cleanup on exit.

The complete create() signature is:

async def create(
    image=None, *, pool=None, name=None, replicas=1, service="server",
    claim_spec=None, keep_alive_minutes=None, api_key=None, local=False,
    runtime=None, cpu=None, memory_mb=None, disk_gb=None,
    region="us-east-1", time_to_start=None, request_timeout=None,
    server_port=8000, telemetry_enabled=True,
) -> Sandbox: ...

ephemeral() accepts the same parameters plus keep_pool=False.

ParameterTypeContract
imageImage or NoneRequired when pool is omitted; mutually exclusive with pool
poolPool, str, or NoneExisting Fleet pool or pool name
namestr or NoneClaim name with pool; pool name for Fleet image-based ephemeral; sandbox name for local/legacy creation
replicasintPool replicas for Fleet image-based ephemeral; default 1
servicestrFleet service to connect to; default "server"
claim_specClaimSpec or NoneExplicit Fleet claim specification
keep_alive_minutesfloat or NoneRenews an acquired Fleet claim's shutdown deadline; positive minutes
localboolSelects local provisioning; default False
runtimeRuntime instance or NoneExplicit local runtime adapter
cpu, memory_mb, disk_gbint or NoneResource overrides where the selected backend accepts them
time_to_startfloat or NoneService startup timeout in seconds
request_timeoutfloat or NoneTransport request timeout where supported
server_portintServer port, 165535; default 8000
api_key, regionstr or None, strLegacy cloud options; region defaults to "us-east-1"
telemetry_enabledboolCreation telemetry option; default True
keep_poolboolephemeral() only: retain the image-created Fleet pool after releasing the claim; requires name

Fleet selection and constraints#

pool= explicitly selects Fleet. It rejects an image, resource overrides, replicas != 1, local=True, an explicit runtime or API key, a nondefault region, request_timeout, or a nondefault server_port. Configure the pool through Pool.apply() or Pool.reconcile() instead.

For image-based calls, Fleet is selected when Fleet authentication is configured, no per-call api_key is supplied, the image resolves to a Fleet registry image, and neither local=True nor a runtime is supplied. Persistent Fleet creation requires an explicitly named pool: Sandbox.create(image) rejects this path. Sandbox.ephemeral(image) can create a disposable pool and claim. Fleet image-based provisioning rejects disk_gb, a nondefault region, and request_timeout.

The presence of an image constructor does not establish backend support. See the Fleet image constraints.

Lifecycle and ownership#

Fleet pool configuration and claim lifetime are separate resources.

OperationFleet effect
await pool.claim() or await Sandbox.create(pool=pool)Acquires a claim; caller owns its release
async with pool.claim()Acquires a claim and calls close() on exit
async with Sandbox.ephemeral(pool=pool)Releases the claim on exit; retains the supplied pool
async with Sandbox.ephemeral(image)Releases the claim and deletes its created pool/template on exit, unless keep_pool=True
await sb.disconnect()Closes the connection; does not release the claim
await sb.close()Releases a Fleet claim and disconnects; repeated calls are safe
await pool.delete()Deletes the pool; also deletes the template owned by that Pool.apply() result

destroy() is the local/legacy transport cleanup method. It does not release a claim obtained through Pool.claim(); use close() for that claim. Local and legacy ephemeral() call destroy() on exit, or suspend when the instance has snapshots. Cleanup can fail; it is not a guarantee of deletion.

Reconnection and renewal#

These methods apply to Fleet claim-backed instances:

MemberSignature or typeContract
claim_namestr or NoneClaim identity, distinct from the bound sandbox's name
pool_namestr or NonePool owning the claim
to_dictto_dict() -> dict[str, Any]Serializes claim identity and service, not credentials or a snapshot
from_dictSandbox.from_dict(data)Awaitable/context manager that reconnects; context exit disconnects without release
keep_aliveasync keep_alive(*, minutes: float) -> NoneMoves the shutdown deadline to now plus positive minutes; caller must renew before expiry
closeasync close() -> NoneReleases the claim and disconnects

The serialized shape is:

{
    "version": 1,
    "provider": "fleet",
    "namespace": "example-pool",
    "pool": "example-pool",
    "claim": "example-claim",
    "service": "server",
}

Sandbox.from_dict() requires the namespace to match the pool. It still requires Fleet credentials and a claim that exists. Serialization, renewal, and close() raise NotImplementedError on instances without a Fleet claim handle.

Other Sandbox methods#

Sandbox.connect() supports await and async with; context exit disconnects. For durable Fleet claim reconnection, use the serialized reference above.

def connect(
    name: str, *, api_key=None, local=False, ws_url=None, http_url=None,
    container_name=None, cpu=None, memory_mb=None, disk_gb=None,
    region="us-east-1", telemetry_enabled=True,
): ...

The lifecycle class methods accept keyword-only local=False, api_key=None:

MethodReturn typePurpose
await Sandbox.list(...)list[SandboxInfo]Lists local sandboxes, legacy VMs, or Fleet pools according to backend selection
await Sandbox.get_info(name, ...)SandboxInfoGets metadata
await Sandbox.suspend(name, ...)NoneRequests backend-specific suspension
await Sandbox.resume(name, ...)SandboxRequests resume and connects
await Sandbox.restart(name, ...)SandboxRequests restart and connects
await Sandbox.delete(name, ...)NoneRequests backend-specific deletion

These name-based operations are backend-specific. For an explicitly acquired Fleet claim, use close() to release it and Pool.delete() to remove its pool.

The connected instance also provides these methods:

MethodReturn typePurpose
await sb.screenshot(text=None, format="png", quality=95)bytesCaptures PNG or JPEG bytes; text is unused in this release
await sb.screenshot_base64(text=None, format="png", quality=95)strCaptures a base64 screenshot
await sb.get_environment()strReports the transport's environment
await sb.get_dimensions()tuple[int, int]Returns width and height in pixels
await sb.get_display_url(share=False)strReturns a display URL where the transport supports it; shared links may embed credentials
await sb.snapshot(name=None, stateful=False)ImageBackend-specific snapshot operation; not implemented for Fleet claim-backed instances

SandboxInfo has required string fields name, status, and source, plus optional string fields os_type, host, vnc_url, api_url, and created_at.

Interfaces and Localhost#

Sandbox exposes shell, files, mouse, keyboard, screen, clipboard, tunnel, terminal, window, mobile, services, and apps. Availability depends on the connected transport. exposed_ports maps local guest ports to host ports; Fleet publishes named services instead.

Localhost.connect() supports await and async with and controls the host through cua_auto, without a sandbox. Context exit disconnects. Its interfaces include screen, mouse, keyboard, clipboard, shell, window, and terminal. See Sandbox interfaces.