Tovább a tartalomhoz

Rigs

Ez a tartalom még nem érhető el a jelenlegi nyelven.

Facts only. For the model behind them, read Rigs and enclosures; to open a machine, follow the guide.

Surface Drives Backend Value Contained egress
Terminal (exec) A shell over the VM’s exec channel microVM smolvm Yes
Browser Headless Chromium (CDP), Firefox (WebDriver BiDi) or WebKit (W3C WebDriver) microVM smolvm Yes
Computer X11 desktop: input via the hypervisor, capture via the guest agent QEMU qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (unaccelerated fallback, never chosen automatically) Yes
Android Android over ADB Google’s emulator android-emulator No — the emulator manages its own networking
iOS iOS Simulator through WebDriverAgent CoreSimulator ios-simulator No — networking follows the host Mac

The terminal and the computer_use surface share the computer surface value; the terminal is distinguished by its exec image marker and is never reused as a drivable desktop (or vice versa). One conversation reuses one terminal machine.

Engine Value Protocol Live view Stills
Chromium chromium (default) Chrome DevTools Protocol Screencast — the browser pushes frames as the page repaints JPEG
Firefox firefox WebDriver BiDi Polled stills (BiDi has no screencast), capped at 6 fps JPEG
WebKit webkit W3C WebDriver (classic) Polled stills, transcoded by the host’s ffmpeg PNG

A rig runs one engine for its whole life. One conversation can hold one rig per engine, which is what makes a side-by-side comparison possible: opening “Firefox (VM)” beside “Chromium (VM)” is two machines, and closing one leaves the other running.

Pass engine to rig.open or to the browser_use tool. An unknown name is refused rather than defaulted — asking for a browser and silently getting a different one answers a compatibility question with the wrong answer.

Engine-specific limits, stated rather than worked around:

  • Firefox has no cache-bypassing reload (it rejects BiDi’s ignoreCache outright), so a hard reload is a normal reload.
  • WebKit has no cache-bypassing reload either, no console feed (output is captured by hooking console.* after each navigation, so anything logged during load is missed — every console extract says so), and needs ffmpeg on the host for its live view.
  • Neither exposes a platform accessibility tree over its protocol, so extract (a11y) returns a DOM-derived approximation, labelled as one.
  • Neither can take a real file drop; a file input can still be pointed at paths inside the machine.
Surface Image Fetched
Terminal ubuntu:24.04, digest-pinned Automatically on first boot, via the machine’s own gated network
Browser (Chromium, Firefox, WebKit) debian:trixie-slim, digest-pinned, plus the engine’s own packages Automatically on first boot, then cached as a warmed pack
Computer A qcow2 desktop image with Chromium, Firefox, WebKit and the same GitHub-hosted-runner CLI baseline the terminal warms Import under Settings → Server → Rigs (checksum-pinned downloads where published)
Android Google’s system images Through the Android SDK
iOS An Xcode Simulator runtime plus checksum-pinned WebDriverAgent Runtime through Xcode; automation bridge from Settings → Server → Rigs

After the first boot of each microVM kind the server caches a pre-extracted copy under the data directory and boots every later machine from it — including pre-warmed images with the packages already installed. The terminal warms a GitHub-hosted-runner-style CLI toolset (git, gcc, python3, jq, rsync, archive tools, and the rest of the apt baseline; not Docker or language toolcaches). The Computer qcow2 bakes the same CLI names in at image build, next to XFCE and the three browsers. Every browser warms its engine. All three engines share a Debian base but never share a pack: the cache is keyed on the image, the engine and an audio revision (audio-v1-<engine>), because a machine warmed for one engine — or before PulseAudio and ffmpeg were part of the workload — has none of the other in it. The terminal pack is keyed on a toolset revision (tools-v1) for the same reason: a pack warmed before the compiler was part of the image must not serve a machine that is supposed to have one.

There is no baked automation image worth taking — Chromium’s chromedp/headless-shell compiles both ALSA and PulseAudio out, so it can never emit sound; the only maintained Firefox one is 33× the size of the Debian base and still ships no socat; there is no maintained WebKit one at all. So every engine installs on first start (chromium, firefox-esr, or webkit2gtk-driver) and reaches the Debian archives (deb.debian.org, security.debian.org, cloudfront.debian.net) while doing it. Chromium is the distribution binary launched as chromium --headless=new.

Setting key Overrides
rigs.smolvm.execImage The Terminal (VM) image
rigs.smolvm.browserImage The Chromium Browser (VM) image

Written through the admin-gated workspace settings store (Settings → Server → Rigs → Custom images (this workspace)). The value must be a registry reference — local paths, archives and flag-like strings are refused, both at the field and again at boot. An invalid stored value is ignored loudly and the default boots instead. The image’s own registry (plus known blob-CDN companions for Docker Hub, GHCR, Quay, GitLab and GCR) is admitted through the egress gate for the pull.

Terminal image contract — bash present; git, curl, socat preinstalled or a Debian/Ubuntu apt base (the enclosure installs those three plus a GitHub-hosted-runner-style CLI toolset on first start: compilers, Python 3, jq, archive tools, rsync. Language toolcaches and Docker are not installed).

Browser image contract — a Debian/Ubuntu apt base (or the packages already installed) with bash and socat, plus a chromium binary the server launches itself as chromium --headless=new with DevTools on guest loopback 9223, relayed to guest port 9222. PulseAudio and ffmpeg are installed on first start for the audio lane. Do not build FROM chromedp/headless-shell: upstream headless.gn compiles both ALSA and PulseAudio out, so that binary cannot emit sound. The override applies to Chromium rigs only — the workload command it boots is Chromium’s, and handing it to Firefox or WebKit would launch a binary that is not there. A Firefox or WebKit rig ignores it loudly and boots its pinned image.

Automation ports — every browser machine forwards exactly one host loopback port to guest 9222. Behind it: Chromium’s DevTools and Firefox’s remote agent sit on guest loopback 9223 with a socat relay in front (both bind loopback unconditionally); WebKit’s driver takes a --host and binds the guest NIC itself. Firefox additionally validates the Host header against its own port, so the client sends the guest-side authority rather than the one it dialled.

Every action is parsed totally: a malformed payload returns a message naming the field, never an exception. Observation verbs (marked ○) stay allowed while a human holds control; mutating verbs are refused.

screenshot○, cursor_position○, mouse_move, left_click, right_click, middle_click, double_click, triple_click, left_mouse_down, left_mouse_up, left_click_drag, scroll, key, hold_key (0–60 s), type, wait○ (0–60 s), set_display, clipboard_read○, clipboard_write.

Coordinates are guest pixels in the guest’s current mode; every screenshot states the display size. Key combinations use X11 spellings (ctrl+s, alt+Tab, Return).

clipboard_read takes a selection: clipboard (what ctrl+C fills, the default), primary (X11 select-to-copy) or xdnd (a drag in flight). An empty result is a normal answer for all three. clipboard_write takes text only — images and files travel on the file lane, because an action’s arguments are persisted to the audit log and image bytes have no business there. Clipboard content comes back fenced as untrusted data.

navigate (http/https only), reload (hard optional), stop_loading, click (selector or coordinate), fill, type, key (DOM key names), scroll, mouse_move, drag, left_mouse_down, left_mouse_up, extract○ (a11y | dom | console), screenshot○ (full_page optional), set_viewport (min 320×240), history, wait_for○ (selector, 0.1–30 s), clipboard_read○, clipboard_write.

Extracted page content returns fenced as untrusted data.

The browser has exactly one clipboard, so clipboard_read takes no selection. Both clipboard verbs need a secure context: a page served over plain http:// has no clipboard API at all, and the verb says so rather than reporting an empty one — use type there, which inserts at the caret without going through a clipboard.

tap, swipe (50–5000 ms), type, key (aliases back, home, recents, enter, delete, backspace, tab, escape, search, menu, volume_up, volume_down, power, or any KEYCODE_*), screenshot○, ui_dump○, install_apk (confined to the rig’s worktree and the server data directory), start_app, stop_app, clear_app_data, uninstall_app, open_url, and shell. shell takes an argv list and runs inside Android, never through a host shell; it covers developer diagnostics such as logcat, dumpsys and pm grant.

mobile_use has no clipboard verbs. Since Android 10 only the focused app may read the clipboard.

tap, swipe (50–5000 ms), type, key (enter, backspace, tab, escape, arrow keys or one printable character; optional command, control, option and shift modifiers), home, lock, unlock, screenshot○, ui_dump○, install_app (a simulator .app directory confined to the rig worktree or server data directory), start_app, stop_app, uninstall_app, open_url, and spawn. spawn takes argv and executes inside the simulator through simctl; it never invokes a host shell.

Coordinates are iOS screen points, not screenshot pixels. The live stream keeps the simulator’s fixed size and letterboxes it instead of resizing the device. Host-to-simulator and simulator-to-host text clipboard transfer uses the same per-user, per-direction permission policy as other rigs; files and images are not accepted by the iOS pasteboard lane.

Each rig creates an owned CoreSimulator device and WebDriverAgent session. Closing it stops WebDriverAgent, shuts down and deletes that device, and removes its registry entry. iOS rigs run only on a macOS server with Xcode, an installed iOS runtime and the pinned automation bridge. They expose no audio, microphone, file drop, host shell or enclosed-network guarantee.

Tool Description
rig_list List a workspace’s rigs with surface, status, display and controller
rig_close Destroy a rig and discard its disk
Phase Meaning
provisioning Booting; the status detail carries the current step verbatim
ready Reachable and accepting actions
parked Idle-parked: vCPUs stopped, RAM still resident; the next action wakes it
closing Shutting down
closed Gone; the row survives for the audit trail
failed Died or never came up; distinguishable so the UI can offer retry
Close reason Fired when
requested A person or agent asked
idleTimeout Idle past 2× the idle window, or evicted for memory
ttlExpired The hard lifetime ran out
conversationEnded The owning conversation ended
workspaceGone The workspace was deleted or membership was lost
serverShutdown The server is stopping
backendFailure The hypervisor died underneath it
Value Terminal Browser Computer Mobile
Memory 512 MB 2048 MB (Chromium); 2560 MB (Firefox, WebKit) 4096 MB 4096 MB
vCPUs 2 2 4 4
Hard TTL 8 h 2 h 2 h 2 h
Idle window 45 min 15 min 15 min 15 min
Boot display — 1280×800 1280×800 1080×1920
  • Agent-lane stills are capped at 1280×800; the human lane negotiates up to 2560×1600.
  • The host’s resident-memory budget for all rigs defaults to 12 GB, counted in resident megabytes (a parked VM still holds its RAM). Eviction is least-recently-used and never takes a machine someone is driving, watching, or has a terminal open in.
  • An open terminal or watch lane pins the rig against parking and idle reaping; the hard TTL still applies.
Port Where Reserved for
7911 Terminal guest The port multiplexer every forward rides
9222, 9223 Browser guest The automation relay and endpoint (WebKit binds 9222 directly and uses no relay)
80, 443 Browser guest loopback The dev-domain HTTP/HTTPS lanes
  • Discovery polls the terminal guest’s listening TCP ports every ~4 s, server-side.
  • At most 16 ports are auto-forwarded per rig; more are listed in the log, not forwarded.
  • The host-side forward binds loopback, preferring the guest’s own port number; Share on local network adds an OS-assigned LAN port.
  • Dev domains must match name.test or name.localhost (lower-case, max 63-character label). One domain maps to one port.
  • Dev-domain HTTPS uses a server-local CA (EC P-256, under <dataDir>/rigs/tls/, keys 0600 and never in a guest) with one wildcard leaf for *.test / *.localhost. No openssl on the host means no HTTPS lane; plain HTTP still routes.
Surface Default allowlist
Terminal The sandbox developer baseline (forges, package registries, model providers) + the Ubuntu apt mirrors + the worktree’s own forge host
Browser usectrl.dev (the product site) — plus the Debian archives on every engine’s first boot, while it installs its packages. The home page is a local file:// document and needs no egress
Computer Empty — deny everything — until a caller grants hosts
Mobile Not enforced (emulator-managed networking)

Every microVM additionally gets its image’s registry hosts, for the pull only. The credential broker’s allowed-hosts set is derived from the same allowlist: no token is minted for a host the guest cannot reach.

Both directions of copy/paste, and dragging files in and out. Available to a person driving a rig; an agent gets the clipboard through the verbs above and no file transfer at all (it already has a shell inside the enclosure).

Clipboard crossing is per-user and per-direction. Host-to-rig paste is allowed by default; rig-to-host copy prompts (a ten-minute grant, or always allow under Settings → Server → Rigs → Clipboard access). The two choices are independent and are never a workspace setting.

Lane Route Carries
Clipboard GET/POST /rig/clipboard/<rigId> Text, one PNG/JPEG (≤16 MB), and the guest paths of files on the clipboard
Files POST /rig/files/<rigId> Up to 64 files, ≤256 MB each and ≤512 MB per drop, with an optional guest-pixel drop point
Files GET /rig/files/<rigId>?p=<base64url path> One file’s bytes, back out
  • HTTP, not RPC. The RPC socket closes a connection on an inbound frame over 256 KB — a DoS guard that is right for JSON commands and fatal for a pasted screenshot. Bytes ride the same kind of route rig frames and meeting audio already do.
  • Auth is the signed target rig-files:<workspaceId>/<rigId> plus workspace membership — a target of its own, so a URL minted to watch a machine cannot also write files into it.
  • Take-over applies. Writing the clipboard and dropping files are mutating and are refused while someone else holds control; reading the clipboard and reading a file out are observation and are not.
  • Where drops land: ~/Drops (desktop), ~/drops (terminal — beside the worktree, never inside it, so a drop never appears as an untracked change), /tmp/cc-drops (browser). The server picks the directory; a caller cannot name it. Existing files are never overwritten — a colliding name lands as 2-name.ext.
  • What the guest is told: a browser page gets a real drop event at the requested point (Input.dispatchDragEvent); a desktop gets the files plus their URIs on its clipboard, because no host can synthesize an XDND drag into an arbitrary toolkit without a privileged in-guest daemon. The reply states which of the two happened.
  • Dragging out is desktop-only and reads the guest’s XdndSelection while a drag is live. A payload identical to what the guest was already holding when the press began is treated as a stale selection from a finished drag, not a new one — X has no “the drag is over” step.
  • Image requirements: the desktop image must be protocol 2 or later (built after clipboard support landed). An older image answers 404 and the app says to rebuild it rather than reporting a broken machine.
  • The audit log records the shape, never the content: clipboard_read, clipboard_write, drop_files and read_file rows carry counts, sizes and paths. A clipboard is where credentials live for a few seconds at a time, and none of it is written down.
  • Rig tools declare the enclosureControl action class (plus networkEgress and processSpawn on the use tools; mobile_use and ios_use also declare packageInstall). rig_close declares enclosureControl; rig_list declares none. Allowed by default; read-only modes deny it wholesale; the per-space autonomy dial can demote it to ask-first.
  • Domain events: RigClosedEvent (with its close reason), RigControlChanged (take-over / hand-back), RigReaped (idle, TTL or memory eviction, with the driving agent). Opening a rig is not an event. See domain events.
  • Storage: rig_sessions and rig_action_log in each workspace database. The action log records every input event with its principal and a monotonic per-rig sequence; typed text is redacted to a length and hash before it is written.
  • Data directory: rigs/images/ (imported qcow2 images), rigs/smolvm/ (per-rig runtime state), rigs/smolvm-packs/ (pre-extracted machine packs), rigs/tls/ (the dev-domain CA), rigs/run/ (QEMU overlays and seeds).
  • Routes: the live view is a tab in a space or PR page; /settings/server/rigs is the Rigs settings screen.