Give an agent a machine to test on
A rig is a throwaway machine an agent opens when it needs to actually try something: load a page, click through a desktop app, tap around a phone. You can watch it work in real time, and take the controls whenever you want.
The machine is a VM. Nothing an agent does inside a rig touches your computer, the VM’s disk is thrown away when it closes, and its network reaches only the hosts you allowed.
Set it up once
Section titled “Set it up once”Rigs run on the machine hosting cc_server — the same machine, not the one
you are looking at. There are four surfaces, and only the last two need any
setup:
| Surface | Runs on | Setup |
|---|---|---|
| Terminal (VM) | A microVM booting a pinned Ubuntu image | None — the image is fetched automatically on first use |
| Browser (VM) | A microVM booting a pinned headless-Chromium image | None — same |
| Computer (VM) | QEMU with a Linux desktop image | Install QEMU (brew install qemu), then Import a desktop image under Settings → Server → Enclosures |
| Phone (VM) | Google’s Android emulator | Install the Android SDK (below) |
The terminal and browser machines boot from digest-pinned images: the exact bytes are named in advance, fetched once on first boot, and cached — after the first boot of each kind, later machines skip the download entirely and come up in seconds. Settings → Server → Enclosures shows what your server can boot and every machine running right now.
The phone is set up differently
Section titled “The phone is set up differently”There is no image of ours for Phone (VM), and that is not an omission. The other surfaces boot machines we can define; Android runs on Google’s emulator, whose system images come from their SDK under their licence. Install Android Studio (or the command-line SDK tools), add a virtual device in its Device Manager, and start it — the Enclosures page then reports the mobile surface as available.
It also tells you exactly which step you are missing — no SDK, no emulator, no
virtual device, or a device that simply is not running — because those have
four different fixes and only one of them is a download. If you start
cc_server from a shell that cannot see the SDK, export it:
export ANDROID_HOME="$HOME/Library/Android/sdk"Open a machine
Section titled “Open a machine”Machines live as tabs, next to the chat and the diff — in a space or on a
PR page, in the same + menu as Terminal and Browser:
- Computer (VM) — a Linux desktop
- Browser (VM) — a headless Chromium
- Phone (VM) — an Android device
Pick one and press Start the machine. The tab says which stage the boot is in (“Starting the microVM”, “Waiting for the guest to come up”) rather than just spinning.
The tab is scoped to that conversation, and so is the agent. Open Browser (VM)
in a conversation and an agent calling browser_use in the same conversation drives
that machine — you are both looking at one screen rather than at two copies of it.
The picture is sized to your panel: drag it wider and the guest changes resolution to match. It is a genuinely different stream from the one the agent sees — the agent gets small, cheap screenshots, you get a full-resolution live view, and neither is compromised for the other. Switch to another tab and the stream stops so a background machine costs you nothing.
A rig tab does not start a machine by itself, including when the app restores your tabs at launch — three VMs booting because you opened the app would be an expensive surprise.
Take the controls
Section titled “Take the controls”Press Take control in the tab’s header. The agent keeps watching and can still take screenshots, but it cannot type or click until you hand back. The status tag changes to You have control and everything you do is recorded against your name.
Press Hand back when you are done, or the power button to stop the machine.
Control is exclusive on purpose: two actors typing into one machine produces input neither of them meant.
Move things in and out
Section titled “Move things in and out”Copy and paste work in both directions across the rig canvas, and so does dragging files.
Copy and paste. Press the copy chord over the canvas and whatever the machine copied — text, an image, a list of files — lands on your clipboard. Paste sends yours the other way and presses paste inside the machine. On macOS the chord is ⌘C/⌘V; ⌃C still reaches a guest shell as an interrupt. On Windows and Linux use ⌃C/⌃V — the guest receives the same keystroke it would have anyway, so ⌃C in a guest terminal still interrupts and your own clipboard is left alone.
Nothing syncs in the background. A password you copy on your own machine does not arrive inside a VM because a timer fired; it crosses when you paste.
Drag files in. Drop them anywhere on the canvas.
- On the Browser (VM), the page receives a real drop at the point you let go, so an upload zone behaves exactly as it would with a local file.
- On the Computer (VM), the files land in
~/Dropsand their paths go on the machine’s clipboard, so ⌃V pastes them into a file manager or an upload field. A host cannot synthesize a drag into an arbitrary Linux app without running a privileged daemon inside the VM, which rigs deliberately do not have — so the toast tells you where the files went rather than pretending a drop happened. - On a terminal, the file is copied in and its path is typed at the prompt, ready to pass to a command. Pasting an image into a terminal does the same thing: it is saved in the machine and you get the path.
Drag files out works from the Computer (VM). Start dragging a file inside the machine, carry the pointer out of the canvas, and it becomes a real drag on your desktop — drop it in Finder or Explorer. Copying files in the machine’s file manager and pasting on your side works too. The Browser (VM) does not offer this: a headless browser has no drag payload to read, and guessing from the page’s text selection would hijack ordinary clicks.
Terminals inside a rig
Section titled “Terminals inside a rig”The terminals in a space or on a PR page can run inside a rig instead of on the server’s own machine. When they do, the panel shows an Enclosed VM badge.
What changes:
- Nothing you run reaches the host. A
rm -rfin there costs you the rig. - The network is deny-by-default. Only hosts on the rig’s allowlist are reachable, and everything goes through a gate that enforces it.
git pushstill works. The rig has no stored credential; it asks the server for a short-lived one per operation, and that token is revoked when the rig closes.
What to know:
- A restored enclosed terminal waits for you. Like a rig tab, a
microvmterminal that comes back with your layout shows an Open the shell button rather than booting its VM at launch. A host-shell terminal costs a process; an enclosed one costs a machine. - Files dropped on the terminal are typed, not opened. Drop a CSV on an enclosed terminal and it is copied into the machine and its guest path appears at the prompt — the host path would be a command that fails there.
- The copy in the rig is a copy. Your worktree on the host stays the source
of truth. Commits you make inside a rig are carried back into
refs/rigs/<id>/*when you ask — they never move your branch or touch your working tree. - Host-target work still runs on the host. A Linux guest cannot build for
macOS or run
xcodebuild. Pick the native backend explicitly for that; the app will ask you to confirm rather than switching quietly.
Run a dev server in the Terminal (VM) — pnpm dev on port 3000, say — and
within a few seconds the plug icon in the terminal’s corner lights up: the
port is forwarded to localhost:3000 on your machine, reachable at
localhost:3000 inside the Browser (VM), shareable on your network, and
nameable as https://myapp.test. The whole flow — auto-forwarding, LAN
sharing, dev domains with HTTPS — is its own guide:
Forward ports from an enclosed terminal.
Custom images
Section titled “Custom images”A workspace can point the Terminal (VM) and Browser (VM) at its own images — under Settings → Server → Enclosures → Custom images. Typical use: extend the default image with the toolchain your project needs so every terminal starts ready, or reuse an image your team already publishes.
The machine still boots inside the same enclosure: same egress gate, same credential broker, same lifecycle. Only workspace admins can change the setting, new machines pick it up (running ones keep theirs), and the reference must be a registry image — local paths are refused.
What an image must provide:
- Terminal (VM) — a Linux image with
bash. It also needsgit,curlandsocat— either preinstalled, or installable on first start (any Debian/Ubuntu-based image works: they are installed automatically). Guest port7911is reserved for the port forwarder. - Browser (VM) — an image with the headless-shell layout: the Chromium
binary at
/headless-shell/headless-shell, plusbashandsocat. The easiest way to get that is to buildFROM chromedp/headless-shell:stableand add what you need. The server starts the browser itself and expects its DevTools endpoint to be relayed on guest port9222— with that layout, it wires this up for you. Guest ports9222/9223are reserved.
Two recommendations: pin the reference by digest (@sha256:…) so the bytes
cannot change under you, and host it on Docker Hub or GitHub Container
Registry — those registries’ download hosts are admitted through the egress
gate automatically; others may need their content delivery hosts reachable to
pull.
When a rig goes away
Section titled “When a rig goes away”Rigs are meant to be temporary:
- Idle — after ~15 minutes with nothing happening it parks (frozen, wakes instantly on the next action). After twice that, it closes.
- Time limit — every rig has a hard lifetime it cannot extend, whatever it is doing.
- Memory — if the server needs room for a new rig it closes the least-recently-used one. A rig somebody is driving, watching, or has a terminal open in is never taken.
When a rig closes, its disk is discarded. Carry anything you want to keep back first.
What a rig can reach
Section titled “What a rig can reach”By default: nothing outbound. You grant hosts explicitly, and the guest’s only route to the network is a gate that enforces that list. The credential broker uses the same list — the server will not hand a rig a token for a host it cannot reach.
Two honest caveats:
- The mobile surface is less contained. An Android emulator manages its own networking, so its egress is not fully enforced the way the browser and desktop surfaces are. Full enforcement needs a Linux worker.
- Everything a rig reads is untrusted. Page text, DOM, accessibility trees and view dumps come back to the agent wrapped in markers that say “this is data, not instructions”. A page that tries to give your agent orders reads as a quoted string.
You can see everything running, and stop any of it, under Settings → Server → Enclosures.
Related
Section titled “Related”- Rigs and enclosures — the model behind all of this: why VMs, the two display lanes, the credential broker, the lifecycle
- Forward ports from an enclosed terminal — reach a dev server from anywhere it matters
- Rigs reference — every surface, verb, port and default in one place
- Configure guardrails —
Drive an enclosure (rig)is an action class you can set to allow, ask-first or deny, per workspace, agent or space. Read-only modes deny it outright.