# Acknowledgments (/docs/acknowledgments) The macOS warm pool is built on a fork of [lume](https://github.com/trycua/cua/tree/main/libs/lume), the VM orchestrator from [cua](https://cua.ai). We've diverged heavily — different scheduling, different networking, different lifecycle — but the Sequoia base image and the initial VZ plumbing came from there. Thanks ❤️ to the cua team for open-sourcing it. # Lifecycle (/docs/concepts) ## Why not sandboxes measured per second? [#why-not-sandboxes-measured-per-second] Because these are real Apple devices, not generic Linux VMs. Apple's macOS software license allows leasing Apple Software and Apple-branded hardware for permitted developer services, but the lease period must be at least 24 consecutive hours ([AWS implements the same floor for the same reason](https://aws.amazon.com/ec2/instance-types/mac/faqs/)). That makes per-second public billing the wrong abstraction for us. So use.computer sells **reservations**: you reserve one or more physical Mac minis for at least 24 hours, and then create/destroy as many sandboxes as you need inside that reservation. The sandboxes still feel ephemeral — warm macOS VMs can be claimed in under a second and destroyed when idle — but the billing and isolation boundary is the Mac mini reservation. ## Reservation [#reservation] A reservation is a contract for N Mac minis for X hours. You pay up front (hourly rate × N × X) at the model's configured rate shown in the live dashboard. Activation binds physical Mac mini IPs to your reservation. Your account API key starts with `uc_live_*` and is managed in Settings. The plaintext key is available to copy from Settings. The gateway stores a SHA-256 hash for inbound auth. When an account has one active Mac reservation, `create()` can infer it; if you have multiple active Mac reservations, pass `reservation_id` so the sandbox is constrained to the right Macs. While the reservation is active, the gateway will only schedule sandboxes for *you* on those Macs. Choose the Mac model when reserving with `mac_model`: `m4` (the default; 10 cores, 16 GiB), `m4-pro` (12 cores, 24 GiB) or `m5-pro` (Apple M5 Pro, Mac17,16; 15 physical CPU cores, 24 GiB, nominal 512 GB SSD). You reserve the whole Mac in every case, for at least 24 hours. Check the live dashboard for each model's current price and availability; a reservation keeps the rate it was bought at, including for later edits. Each sandbox create picks its own size with `cpu`, `memory_gib` and `disk_gib`. The sandboxes on one Mac can together use all of its cores and all of its memory, with at most two sandboxes per Mac. On an M4, for example, 7 vCPU + 3 vCPU works, and so does 4 GiB + 12 GiB. Fields you leave out use the model/layout defaults below. The smallest sandbox is 2 vCPU / 4 GiB, and `disk_gib` must be the image's disk size: disks are not resized at create. A create that doesn't fit is refused with `resources_exceed_mac` (bigger than the whole Mac), `insufficient_capacity` (bigger than what your other sandboxes leave free) or `sandbox_limit_reached` (the Mac already runs two). `vm_layout` picks which VMs are pre-booted. On an M4, `split` (the default) keeps two 5 vCPU / 8 GiB VMs warm, and `whole` keeps one 10 vCPU / 16 GiB VM warm. On an M4 Pro, the sizes are two 6 vCPU / 12 GiB VMs or one 12 vCPU / 24 GiB VM. On an M5 Pro, split is **8 + 7 cores · 12 GiB each**, and whole is one 15 vCPU / 24 GiB VM. Whole runs one sandbox at a time. Custom 7 vCPU / 12 GiB plus 8 vCPU / 12 GiB VMs can coexist on a split M5 Pro. An M5 Pro default create or snapshot restore takes whichever split slot is available and reports its actual 7 or 8 vCPUs and 12 GiB; it does not promise the first slot or preserve a snapshot source's CPU count. Existing reservations may retain earlier warm profiles until their Macs become idle, including M4-sized pools on an M4 Pro and legacy 12 GiB whole VMs. Their workloads and reservation end times stay unchanged; new reservations require the model's current profile. New macOS 26.2 base images are `base-macos-26` for split and `base-macos-26-whole` for whole. Use the reservation-scoped `/v1/platforms` catalog to discover currently available images and capacity; existing image names remain valid where offered. On M5 Pro, the split base's 8 vCPU / 12 GiB settings seed only the first producer profile: the pool sizes the second clone to 7/12. The whole profile is 15/24. These are macOS 26.2 guest bases; the catalog, not the host OS version, determines guest image availability. Reservation edits accept `vm_layout`; leaving it out preserves the current layout. Stop all sandboxes before changing layout. A layout change does not itself change the reservation price. ## Warm pool (macOS) [#warm-pool-macos] Each Mac mini keeps a warm pool sized for its reservation layout: two split VMs or one whole VM. When you call `create()` without a size, or with the warm VMs' size, the gateway picks a warm VM on one of your Macs, marks it occupied, and returns a `sandbox_id` with `boot: "warm"`. Any other size resizes a warm VM and boots it, which takes as long as a macOS boot (a minute or two); the response says `boot: "cold"`. When your sandboxes leave too little room for the Mac's other warm VM, the gateway stops that VM and keeps it aside, so the VMs running on your Mac never add up to more than it has; your next sandbox boots from it, and it goes back to the warm pool once there is room. When you `delete()` (or your sandbox times out), the gateway throws away the dirty VM and clones a fresh one in the background. The next caller already has a warm VM waiting. ## Idle reaper [#idle-reaper] Sandboxes that go \~2 minutes without an HTTP touch, SSH session, or VNC connection are reaped automatically. For long exec or downloads, send a `keepalive` heartbeat from a sidecar thread. ## End of reservation [#end-of-reservation] When `end_at` passes: * All your sandboxes are destroyed. * The account API key stays valid for future reservations. * The Macs go back into the available pool. * Your row moves to "Past reservations" in the dashboard. # Introduction (/docs) use.computer gives you macOS sandboxes: VMs on dedicated Apple M4, M4 Pro and M5 Pro Mac minis that you reserve for 24 hours or more. Reserve an M4 (10 cores, 16 GiB), an M4 Pro (12 cores, 24 GiB) or an M5 Pro (15 cores, 24 GiB), then size each of up to two VMs per Mac as you like. The live dashboard shows each model's configured price and availability; existing reservations retain their purchased rate. M5 Pro's default split warm pool is **8 + 7 cores · 12 GiB each**; whole provides one 15 vCPU / 24 GiB VM. Default creates and snapshot restores take the available slot and report its actual resources. See [reservations](/docs/concepts#reservation) for all model profiles. ```bash pip install daytona-use-computer ``` ```python from use_computer import Computer client = Computer(api_key="uc_live_...") mac = client.create() # warm macOS VM, under a second mac.exec("open -a Safari https://example.com") mac.mouse.click(640, 480) mac.keyboard.type("hello from your agent") print(mac.vnc_url) # watch it live in your browser mac.delete() ``` TypeScript ([`@daytona/use-computer`](https://www.npmjs.com/package/@daytona/use-computer)) exposes the same surface; see [SDK & API](/docs/sdk). Beyond driving sandboxes, any session can be captured as a replayable [trajectory](/docs/trajectories), and [snapshots](/docs/sdk#snapshots) let every run start from the same seeded macOS state. # Performance (/docs/performance) Real numbers, measured against the dev cluster on a wired 5 Gbps LAN. WAN adds \~30 ms of round-trip on top. ## Sandbox open [#sandbox-open] | Platform | P50 | P95 | P99 | | ------------ | ------ | ----- | ----- | | macOS (warm) | 385 ms | 3.4 s | 6.4 s | macOS sandboxes come out of a warm pool — P50 is the steady state. P95/P99 cover the case where the warm slot was just claimed and the pool is busy cloning the next VM. ## Input — mouse & keyboard [#input--mouse--keyboard] Round-trip from `client.method()` to ACK from `cua-server` inside the macOS VM. | Method | P50 | P95 | P99 | | --------------------- | ------ | ------ | ------ | | `mouse.click` | 98 ms | 165 ms | 433 ms | | `mouse.move` | 93 ms | 163 ms | 545 ms | | `mouse.get_position` | 97 ms | 117 ms | 550 ms | | `keyboard.type` | 95 ms | 112 ms | 441 ms | | `keyboard.press` | 92 ms | 160 ms | 531 ms | | `keyboard.hotkey` | 96 ms | 116 ms | 446 ms | | `display.get_windows` | 239 ms | 409 ms | 720 ms | ## Screenshot & composite ops [#screenshot--composite-ops] `screenshot` returns a PNG of the full display. `act` does click-then-screenshot in a single round-trip; `agent_loop` is the same shape an agent sees per step. | Method | P50 | P95 | P99 | | ----------------------- | ------- | ------- | ------- | | `screenshot` | 1361 ms | 1780 ms | 2243 ms | | `act` (click + screen) | 1392 ms | 1730 ms | 1940 ms | | `agent_loop` (one step) | 1380 ms | 1785 ms | 1912 ms | | `recording.start+stop` | 1353 ms | 1789 ms | 2086 ms | Screenshots dominate every composite op — if you can run with compressed JPEGs or partial regions, do. ## Exec [#exec] Short macOS shell commands (`ls`, `echo`) round-trip in \~80 ms P50. Long commands stream output — no extra overhead until they finish. ## Hardware [#hardware] M4 Mac minis have **10 cores** (4 performance + 6 efficiency), **16 GB RAM** and a **512 GB SSD**. M4 Pro Macs (`mac_model: "m4-pro"`) have 12 cores and 24 GiB. Apple M5 Pro Macs (`mac_model: "m5-pro"`, hardware identifier Mac17,16) have **15 physical CPU cores**, **24 GiB RAM** and a **nominal 512 GB SSD**. Each sandbox picks its size at create, and the sandboxes on a Mac can together use all of its cores and memory. Guest vCPUs map onto the host's cores, so a fully loaded VM shares them with the host's own services. Guest memory also shares physical RAM with the host; heavy allocations can trigger host compression or swap. M5 Pro's split pool is **8 + 7 cores · 12 GiB each**, not two equal-size guests. Whole provides one 15 vCPU / 24 GiB VM. Default creates and snapshot restores take the available slot and report its actual resources; custom 7/12 plus 8/12 VMs can fill the split Mac. These hardware profiles do not establish new latency measurements: the timings above are not M5-specific benchmarks. ## Concurrency [#concurrency] * Per Mac mini: two macOS VMs (one if the reservation uses the `whole` warm pool). * Per reservation: N × 2 VMs for split, N × 1 for whole (N = reserved Macs). * Available Mac capacity is shown in the dashboard; use the reservation-scoped platform catalog for VM availability. # Quick start (/docs/quickstart) Sign up at [use.computer](https://use.computer); new accounts start with **$100 starter credit**, no card required. Copy your account **API key** from Settings. It starts with `uc_live_...`. ```bash pip install daytona-use-computer ``` If you installed the old `use-computer` package, run `pip uninstall use-computer` first: both packages install the same `use_computer` module. The import stays `from use_computer import Computer`. ## 1. Reserve a Mac mini [#1-reserve-a-mac-mini] use.computer gives you macOS sandboxes on dedicated Apple M4, M4 Pro and M5 Pro Mac minis that you reserve for 24 hours or more. Pick an M4 (10 cores, 16 GiB), an M4 Pro (12 cores, 24 GiB) or an M5 Pro (15 cores, 24 GiB), then size each sandbox when you create it. Check the live dashboard for each model's configured price and availability; your starter credit pays for reservations. Reserve one Mac mini from the dashboard, or reserve directly in the SDK: ```python import os from use_computer import Computer client = Computer(api_key=os.environ["USE_COMPUTER_API_KEY"]) # Reserve 1 Mac mini for 24 hours using your starter credit reservation = client.reserve(hours=24, mini_count=1, mac_model="m4") print(f"Reserved Mac mini: {reservation.reservation_id}") ``` Omitting `mac_model` reserves an M4; use `mac_model="m5-pro"` for M5 Pro. Its split pool is **8 + 7 cores · 12 GiB each**, while `vm_layout="whole"` gives one 15 vCPU / 24 GiB VM. Default creates and snapshot restores choose the available slot, so an M5 split sandbox reports either 7 or 8 vCPUs. See [reservations](/docs/concepts#reservation) for sizes, limits and macOS 26.2 guest base images. ## 2. Create and drive a macOS sandbox [#2-create-and-drive-a-macos-sandbox] Once reserved, warm macOS VMs launch in under a second. Drive the sandbox with mouse, keyboard, shell execution, screenshots, and live VNC: ```python import os from use_computer import Computer client = Computer(api_key=os.environ["USE_COMPUTER_API_KEY"]) # Create a warm macOS sandbox (under a second) mac = client.create() # A second sandbox can take what is left of the Mac (here 5 vCPU / 8 GiB); # a size other than the warm VMs' boots cold, in a minute or two # small = client.create(cpu=3, memory_gib=4) # Run shell commands inside the macOS VM result = mac.exec("sw_vers") print(result.stdout) # Type and click mac.keyboard.type("hello from use.computer") mac.mouse.click(x=200, y=300) # Capture a screenshot png = mac.screenshot.take_full_screen() open("/tmp/screen.png", "wb").write(png) # Live viewer URL print(f"Live VNC view: {mac.vnc_url}") # Delete the sandbox when finished mac.delete() ``` You can also use a context manager to clean up automatically on exit: ```python with client.create() as mac: print(mac.exec("hostname").stdout) mac.keyboard.type("automated agent run") png = mac.screenshot.take_full_screen() print(f"Watch live: {mac.vnc_url}") ``` ## 3. View it in your browser (noVNC) [#3-view-it-in-your-browser-novnc] Every running sandbox has a one-click live view. Sandboxes expose `vnc_url` directly, and the dashboard's Sandboxes tab has an **Open** button on every running VM. The viewer is a full noVNC session that you can drive with mouse and keyboard. # SDK & API (/docs/sdk) ## SDKs (Python · TypeScript) [#sdks-python--typescript] Both SDKs ([Python on PyPI](https://pypi.org/project/daytona-use-computer/), [TypeScript on npm](https://www.npmjs.com/package/@daytona/use-computer)) expose the same macOS sandbox surface — `create()` for macOS sandboxes, plus mouse, keyboard, screenshot, exec, files, recording, and the UI tree. Pick your language: | Language | Install | Path | | ------------------- | ----------------------------------- | --------- | | **Python** | `pip install daytona-use-computer` | `python/` | | **TypeScript / JS** | `npm install @daytona/use-computer` | `js/` | A Go SDK is not available yet. These packages replace the old `use-computer` (PyPI) and `use-computer-sdk` (npm) packages, which get no new releases. Uninstall the old package first (`pip uninstall use-computer` or `npm uninstall use-computer-sdk`): the Python packages install the same `use_computer` module, so the import stays `from use_computer import Computer`. In TypeScript, change the import to `@daytona/use-computer`. ```ts // TypeScript — async-native import { Computer } from "@daytona/use-computer"; const mac = await new Computer().create(); console.log((await mac.exec("sw_vers")).stdout); await mac.close(); ``` The rest of this page covers the Python SDK in depth. The TypeScript SDK mirrors the sandbox surface; Python additionally ships optional computer-use agents behind extras. ## Idempotency-Key [#idempotency-key] The customer API accepts `Idempotency-Key` on `POST /v1/sandboxes` and `POST /v1/sandboxes/{id}/snapshots`. Creating a sandbox with a `snapshot` field restores that snapshot and uses the same protection. Use a unique key (up to 255 bytes) for each operation and reuse it when retrying with the same path and exact request body. Keys are scoped to your user and gateway environment across these endpoints. Completed 2xx and 4xx responses replay their original HTTP status and body for 24 hours after the first request. A 5xx response replays only until the attempt's 10-minute create or 25-minute snapshot capture/restore deadline; retrying after that deadline starts a fresh attempt. A concurrent retry returns `409 {"error":"idempotency_in_flight"}`; retry with the same key after the first request finishes. An unfinished request can be retried after 10 minutes for ordinary creates or 25 minutes for snapshot capture/restore. A gateway restart also releases unfinished requests in that gateway environment. These retries may repeat work that completed remotely before the gateway could record its response. Reusing a key with a different path, body, or reservation-key reservation returns `422 {"error":"idempotency_key_reused"}`. Without the header, every request starts a new operation. After 24 hours, the same key starts a new operation too. ## Snapshots [#snapshots] macOS sandboxes can be snapshotted after you seed them, usually by opening the live screen over VNC and setting it up by hand. macOS snapshots preserve disk state. macOS snapshots are portable disk deltas. When you create one, the gateway pulls the snapshot artifact from the source Mac Mini; when you launch from it, the gateway pushes that artifact to whichever reserved Mini claims the new VM. Restores use the base image recorded in the snapshot, not the Mac's current warm-pool image. An older snapshot can therefore restore after a pool upgrade while its original base remains available. Snapshots taken from that restored sandbox keep the same base dependency, including across gateway restarts. If the reservation's Macs lack the required base or have a different base disk size, create returns `409` with `error: "snapshot_base_unavailable"` before claiming a VM. Contact support to recover the base, or create a new snapshot from a fresh sandbox. Transfer, apply, and startup failures return `502` with a JSON error; these are different from a missing reservation. ```python from use_computer import Computer client = Computer(api_key="uc_live_...") # Boot a sandbox and configure it by hand over VNC, then snapshot it. with client.create() as mac: print("Set up the screen here:", mac.vnc_url) # In the VNC session, bake whatever you want into the image: # - install the apps and tools your agent needs # - sign into accounts (email, GitHub, a web app) # - pre-open the tabs, apps, or files it should start from input("Press Enter once the screen is ready to snapshot...") # Save the configured state as a reusable snapshot version. snapshot = mac.snapshot("chrome-seeded-macos") # Every future sandbox boots from that saved state, no setup needed. with client.create(snapshot=snapshot.version) as seeded: print(seeded.vnc_url) # installed apps, files, and logins restored ``` Use `client.snapshots()` to list saved snapshot versions. ## Python SDK [#python-sdk] The Python SDK is published on [PyPI](https://pypi.org/project/daytona-use-computer/). ```bash pip install daytona-use-computer ``` Base installs only the SDK client and `httpx`. Computer-use agent integrations are opt-in: ```bash pip install "daytona-use-computer[agents]" # computer-use agents and provider SDKs ``` ```python from use_computer import Computer client = Computer(api_key="uc_live_...") ``` ### Creating a sandbox [#creating-a-sandbox] ```python mac = client.create() ``` If one account key has more than one active Mac reservation, pass `reservation_id="..."` when creating macOS sandboxes. Reserve with `client.reserve(hours=24, mac_model="m5-pro")` for an Apple M5 Pro Mac (15 cores, 24 GiB). M4 remains the default; M4 Pro is `m4-pro`. Check the live dashboard for each model's configured hourly price and availability. Reservations retain their purchased rate. M5 Pro split defaults are **8 + 7 cores · 12 GiB each**. `create()` and `create(snapshot=...)` use the available slot and return its actual `cpu` and `memory_gib`; a restore is not pinned to the source sandbox's CPU count. `vm_layout="whole"` at reservation time provides one 15 vCPU / 24 GiB VM. For explicit sizes, `create(cpu=7, memory_gib=12)` and `create(cpu=8, memory_gib=12)` can coexist on a split M5 Pro Mac. Use the reservation-scoped platform catalog for guest base availability. ### DSL [#dsl] `MacOSSandbox` provides complete control over the macOS VM (screenshot, display, recording, file transfer, mouse, keyboard, and shell). | Method | Notes | | ------------------------------------------------------- | ---------------------------------------------------------------- | | `screenshot.take_full_screen(show_cursor=False)` | PNG bytes. | | `screenshot.take_region(x, y, w, h)` | PNG bytes of a region. | | `screenshot.take_compressed(...)` | JPEG/PNG with quality control. | | `display.get_info()` | Screen size, scale. | | `display.get_windows()` | Accessibility UI tree of macOS application windows. | | `accessibility.get_tree()` | Typed accessibility UI tree model. | | `recording.start(name=None)` / `.stop(id)` | Start / stop screen recording. | | `recording.download(id, local_path)` | Save mp4 to disk. | | `recording.list_all()` / `get(id)` / `delete(id)` | Manage recordings. | | `upload(local, remote)` / `upload_bytes(data, p)` | Upload a file. | | `download_file(remote, local)` | Download a file. | | `mouse.click(x, y, button="left", double=False)` | Native CGEvent click. | | `mouse.move(x, y)` / `drag(start, end, ...)` | Cursor move / press-move-release. | | `mouse.scroll(x, y, direction="down", amount=3)` | Scroll wheel. | | `mouse.get_position()` | Cursor x, y. | | `keyboard.type(text, delay=None)` | Typed input. | | `keyboard.press(key, modifiers=None)` | Single key + optional modifiers. | | `keyboard.hotkey(keys)` | Multi-key chord (e.g. `"cmd+shift+4"`). | | `exec(cmd, timeout=120)` / `exec_ssh(cmd, timeout=120)` | Shell command via SSH. | | `exec_ax(cmd, timeout=120)` | Runs under cua-server (TCC-granted; needed for AX APIs). | | `act(action: dict, screenshot_after=True, ...)` | Drive any cua-server action; returns the post-action screenshot. | | `upload_dir(local, remote)` / `download_dir(...)` | Tar + push / pull + untar a directory. | ### Lifetime and cleanup [#lifetime-and-cleanup] The server defaults new sandboxes on a reserved Mac to the reservation lifetime when the create request omits `ephemeral`: they live until you delete them or the reservation reaches `end_at`. Set `ephemeral: true` to opt into the two-minute idle timeout. The shipped Python and TypeScript SDK versions still send `ephemeral: true` by default. With these versions, explicitly disable ephemeral mode before removing your keep-alive thread. In Python: ```python with client.create(ephemeral=False) as mac: # automatically delete on exit ... # long-running agent work ``` If you keep the SDK's ephemeral default, keep calling `mac.start_keepalive()` for long-running work. The server's reservation-lifetime default takes effect only once the SDK omits the field (or you explicitly send false). Without a context manager, call `mac.delete()` when finished. At reservation expiry, `GET /v1/sandboxes/{id}` reports `state: "completing"` while cleanup is in progress; you can still delete the sandbox. Once cleanup completes, it returns 404. `vnc_url` from create or snapshot restore contains a sandbox-scoped viewer token, not your account key. The link expires within one hour, or earlier at the reservation's `end_at` (pool sandbox lifetime: 24 hours after creation). Each viewer request checks that the sandbox still exists and its reservation is active, including after reservation edits. The owner can request a fresh link with `POST /v1/sandboxes/{id}/viewer-token`; the response includes `vnc_url`, `token`, and `expires_at`. Anyone holding the link can view and control that sandbox until it expires. ## HTTP API [#http-api] Not on Python? Every SDK method is a thin wrapper over `https://api.use.computer/v1/...` — auth is `Authorization: Bearer uc_live_...`. The full surface is documented as an interactive Swagger viewer at [api.use.computer/docs](https://api.use.computer/docs), with the raw spec at [api.use.computer/openapi.yaml](https://api.use.computer/openapi.yaml) for Postman / Insomnia. # Trajectories (/docs/trajectories) A trajectory is a recorded session on a live sandbox: every click, keystroke, and scroll captured as a typed action, paired with a screenshot and the accessibility tree at each step. Collect them from the dashboard, inspect them step by step, replay them on a fresh sandbox, and export them for evals or training. Trajectory inspector ## Collecting [#collecting] From the dashboard's **Trajectories** tab, click **New trajectory** and write the instruction the demonstration should accomplish. Trajectory collections run on one of your Mac mini reservations. The collector opens the live macOS desktop in your browser: 1. **Setup**: get the sandbox into its starting state. Run shell commands, upload files, open apps. Nothing is recorded yet; setup steps are stored separately from the task. 2. **Record**: click **Start Recording Task** and perform the task by hand. Every click, keystroke, scroll, and drag is captured as a typed action with a screenshot and the accessibility tree before and after. 3. **Finish & save**: the trajectory saves immediately. The screen recording finalizes in the background and appears on the detail page shortly after. ## Inspecting [#inspecting] Each trajectory's detail page shows the step timeline: select a step to see its annotated screenshot (a crosshair marks the action's coordinates), the action as a typed call like `left_click(x=412, y=288)`, the resolved accessibility element it hit, and the before/after accessibility trees. The full screen recording sits below the steps. The instruction, category, and a setup script (`setup.sh`, run before each replay) are editable in place. ## Replaying [#replaying] **Replay** boots a fresh sandbox, runs the setup script, and re-executes the recorded actions. A live VNC link lets you watch the run; if the task has a grader, the reward is reported when the replay completes. ``` POST /v1/me/tasks/{id}/replay -> { id, status, sandbox_id } GET /v1/me/tasks/replays/{replayID} -> poll status until completed/failed ``` ## Exporting [#exporting] Trajectories are stored in **ATIF** (Agent Trajectory Interchange Format): a `task` plus ordered `steps`, where each step carries its `tool_calls` (function + args) and an observation with the screenshot. ``` GET /v1/me/tasks -> list trajectories GET /v1/me/tasks/{id} -> full trajectory (steps, app state, setup) GET /v1/me/tasks/{id}/trajectory -> ATIF JSON GET /v1/me/tasks/{id}/download -> ZIP: trajectory.json + images/ + setup GET /v1/me/tasks/{id}/recording -> screen recording (mp4) ``` Auth is the same `Authorization: Bearer uc_live_...` as the rest of the [HTTP API](/docs/sdk#http-api). The ZIP is self-contained: ATIF JSON, per-step PNG screenshots, task metadata, and the setup script, ready to feed into an eval harness or a training pipeline.