Skip to content
Tech News
← Back to articles

The VMs Powering Mobile Agents (Instinct, Claude Code)

read original get Logitech Keys-To-Go 2 Bluetooth Keyboard → more articles
Why This Matters

Coding agents are migrating from local machines to vendor-run cloud VMs so they can be driven from phones, which shifts both the runtime and the security boundary to the provider. The teardown of Claude Code's environment shows a Firecracker microVM with a Rust init as PID 1, read-only vendor disks separated from user-writable storage, and a MITM'd, 443-only egress gateway with no inbound access.

Key Takeaways
Worth a Look

Logitech Keys-To-Go 2 Bluetooth Keyboard — If your coding agent now lives in a cloud VM you drive from your phone, the bottleneck becomes typing prompts on glass. The Keys-To-Go 2 is a slim, foldable Bluetooth keyboard with a built-in cover that pairs with phones and tablets, so you can fire off Claude Code sessions from anywhere. It slips into a bag as easily as the laptop you no longer need to carry.

See Logitech Keys-To-Go 2 Bluetooth Keyboard on Amazon → Affiliate link — we may earn a commission on purchases, at no extra cost to you. Product picked by AI based on this article; it is not a tested recommendation.

One awesome product evolution is that agents (Claude Code, Instinct, Poke, etc) are moving off our local computers so that we can use them on our phones. Ultimately this is great for the customer because that means the agent companies provide us with VMs for them to run on! Here's some notes on how the major platforms work based on looking around on ws-term.

Claude Code on Your Phone

Claude Code's box is its own Firecracker microVM, a KVM guest with its own kernel, booted straight into an init written in Rust:

$ cat /proc/cmdline ... rdinit=/process_api ... --listen-vsock-port 2024 $ uname -r 6.18.5-fc-v20 # -fc- = Firecracker; a custom-built guest kernel $ ps -o comm -p 1 process_api # PID 1 is not systemd; it's a Rust/Tokio binary

process_api is PID 1 and the host's control agent living inside your VM: it mounts the disks, then listens on vsock port 2024 so the host can drive the session from outside. That's the platform's defining trait: the operator lives inside your tenant space, and a lot of engineering goes into sealing it off (PID 1 is non-dumpable, /proc/1/mem is denied even with CAP_SYS_PTRACE , your shell is missing CAP_SYS_RESOURCE ).

The disks split cleanly into yours (writable, persistent) and theirs (read-only, shared):

$ lsblk -o NAME,SIZE,RO,MOUNTPOINT vda 256G 0 / # yours: writable, survives reclaim vdc 341M 1 /opt/claude-code # theirs: the 324 MB `claude` harness (Bun) vdd 45.6M 1 /opt/env-runner # theirs: the task launcher vde/vdf ... 1 /mnt/skills/... # theirs: skills

The harness is the thing running your tool calls and is a 324 MB compiled Bun binary on a read-only disk. The model runs elsewhere; inference goes out as Server-Sent Events over HTTPS/2 (not a WebSocket) to /v1/messages , through an egress gateway that is 443-only and MITM'd ( CN = Egress Gateway ... (production) ), with api.anthropic.com pinned in /etc/hosts . There is no inbound at all ( 192.0.2.2 , an RFC-5737 test address). Auth is a host-minted OAuth token, cached root-only on disk and rotated per boot.

Lifecycle is host-driven and measured from the inside: ~430 ms to init, ~6.4 s to the harness process. Spin-up is triggered by an inbound message (the host wakes the VM over vsock and runs --session-mode resume ); spin-down is idle reclaim decided by the host. When it's reclaimed, the processes die but vda detaches intact and reattaches on the next cold boot, which is why the conversation feels continuous even though the compute was destroyed.

flowchart TB user(["your keystrokes"]) -->|http post| ingress["session-ingress"] ingress --> pa hostctl(["host control plane"]) -->|vsock port 2024| pa subgraph vm["Firecracker microVM"] pa["process_api, pid 1, Rust"] --> harness["claude, 324 MB Bun harness"] vda[("vda (rw), yours, persists")] --- harness ro[("vdc/vdd/vde/vdf (ro), theirs")] --- harness end harness -->|inference over SSE| gw["egress gateway, 443, mitm, api.anthropic.com"]

... continue reading