Use cases
Each case below was run in a real VM.
Claude Code in the browserβ
An agent with no brakes, in a box. Claude Code runs inside a MicroVM with --dangerously-skip-permissions: it edits,
installs and executes without asking, because whatever goes wrong stays in the VM.
rc machine create --name agent --image node:22 --net -e IS_SANDBOX=1 \
--init "npm install -g @anthropic-ai/claude-code"
rc machine start --name agent
rc machine web-terminal --name agent -- claude --dangerously-skip-permissions
β― Write a tiny Python web server that answers "hello from the playground" on port 8000, start it in the background and check it with curl.
Ran 2 shell commands
β curl isn't installed here, so I'll check the server with Python's HTTP client instead.
Ran 1 shell command
β The server is running in the background on port 8000 and answers hello from the playground. I couldn't check it with curl because curl isn't installed in this environment. Instead I fetched the page with Python's built-in HTTP client and got 200 text/plain with that text.
- Code: /tmp/demo/server.py uses only Python's standard library and answers any GET request.
- Log: /tmp/demo/server.log records each request.
To check it with curl yourself, install it first (for example ! apt-get install -y curl), then run curl localhost:8000. To stop the server, run pkill -f server.py, or kill its process ID if pkill isn't available either (pgrep wasn't).
β» Churned for 15s Β· done 4:18 PM
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β―Β install curl and check it ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β΅β΅ bypass permissions on (shift+tab to cycle)
| What | How |
|---|---|
| project | the host folder mounted at /workspace: what the agent writes shows up there |
| terminal | rc machine web-terminal: 127.0.0.1 only, with a token in the URL |
| root without confirmation | IS_SANDBOX=1 in runner.code; without it Claude refuses --dangerously-skip-permissions as root |
| ports | any server the agent starts (uvicorn, Vite, a database) becomes a tab at the end of the bar, with the app inside, and answers on your computer's 127.0.0.1. The shell tab gives a separate terminal and eventos shows what opened and closed |
| SSH | [auth] ssh_agent = true: git push with the host's keys, which never enter the VM |
| login | once, via the subscription /login or an API key; it lives in /root/.claude on the machine's disk and survives a stop |
| resume | closing the tab stops nothing; to pick up after exiting: rc machine web-terminal --name agent -- claude --dangerously-skip-permissions --continue |
| API key that never enters the VM | --credential [email protected]:set-header=x-api-key |
Every tab open on the same URL shares one PTY: resizing one window changes the size for all of them.
Try it: claude-in-chrome.runner.codesβ
The same terminal, published: at claude-in-chrome.runner.codes each
visitor gets a machine of their own with Claude Code open and no permission prompts. You run /login with your own
account, and the login stays on your machine only.
https://8000-<id>.runner.codes/.| What | How |
|---|---|
| machine | one Fly Machine per visitor (Fly exposes no /dev/kvm, so the microVM is Fly's), 2 vCPUs and 2 GiB |
| who you are | the browser visitorId (FingerprintJS v3, MIT) only picks which machine is yours; the terminal token is a server HMAC |
| ports | any server you start answers at https://<port>-<id>.runner.codes/ and becomes a tab |
| network | open internet; the Fly private network and the /.fly/api proxy are closed to the visitor |
| limit | 3 machines; with all of them in use the page says "playground is full" |
| time | 30 min idle stops it; 24 h without use deletes the machine and its disk |
The code lives in cmd/rc-playground (the front), cmd/rc-visitor (inside each machine) and
deploy/playground/flake.nix (the images, built with Nix). The step-by-step operation is in the runbook, section 8w.
Code playgroundβ
Exercises, auto-grading, documentation sandboxes: each submission runs in a fresh MicroVM, with no network, and is gone at the end. 15 languages through the same route, 26β43 ms per request with the pool warmed. See the HTTP API.
rc serve --listen 127.0.0.1:8080 --pool-size 2
curl -s -X POST http://127.0.0.1:8080/api/v1/run -H 'content-type: application/json' \
-d '{"language":"python","stdin":"oi","files":[{"name":"main.py","content":"print(input().upper())"}]}'
Local LLM on the GPUβ
llama.cpp with Vulkan inside the VM, talking to the host GPU through virtio-gpu (Venus β MoltenVK β Metal): 56.7 tokens/s on the GPU versus 10.3 on the CPU (Qwen2.5 0.5B). No host directory is mounted unless you declare a volume. Details in GPU.
Desktop in the browserβ
The browser screen (--display), with keyboard and mouse, at http://127.0.0.1:6080: for testing a GUI app or letting an
agent use a screen. Details in Display in the browser.
Desktop with Claude Code, operated by an agentβ
examples/desktop-claude/runner.code
sets up an XFCE desktop in the microVM: black background, the Arquivos, Claude, Navegador and Terminal shortcuts, Firefox
as the default browser and Claude Code installed. The screen follows the browser window, every application opens
maximized, and a logout brings the session back on its own.
cd examples/desktop-claude
rc machine create --name desk
CLAUDE_CODE_OAUTH_TOKEN=... rc machine start --name desk # the guest only sees a placeholder of the token
open http://127.0.0.1:6080
From there, three ways to send work to that VM's Claude, all through the Go SDK
(examples/desktop-claude-agent):
claude -p via exec (answer in JSON), the task typed into its window, or typed through the screen API. And, with
rc mcp, the Claude Code on your machine operates the VM's screen the way it operates
a browser: screenshot, click, keyboard.