Requirements
| Requirement | Details |
|---|---|
| Hardware | Apple Silicon Mac, M1 or later (tested on M4). |
| macOS | A version QEMU supports: the current one and, for up to two years, the previous one (tested on macOS 15). |
| Runtime | QEMU from Homebrew. The installer handles it, installing Homebrew too if needed. |
| Memory | 4 GB per running Ubuntu or Arch VM, 8 GB per running Windows VM. |
| Disk | ~10 GB per Ubuntu or Arch image, ~30 GB per Windows image, each including its snapshot. |
Install
curl -fsSL https://agentpc.pawanpaudel.com.np/install.sh | sh
The installer:
- downloads the latest release and verifies its checksum,
- installs
agentpcto~/.local/bin(nosudo) and adds it to yourPATH, - installs QEMU with Homebrew if it's missing (installing Homebrew first if needed, which asks for your password once),
- registers the MCP server with the agents it finds,
- checks everything with
agentpc doctor.
Upgrade later with agentpc update. Installer options:
| Variable | Effect |
|---|---|
AGENTPC_VERSION=0.1.0 | Install a specific version. |
AGENTPC_INSTALL_DIR=<dir> | Install somewhere other than ~/.local/bin. |
AGENTPC_NO_MCP=1 | Skip registering the MCP server. |
Images
Every VM is a copy-on-write clone of a read-only image, so it starts from a clean
install and costs only a few MB. A bare ubuntu means
ubuntu-24.04, a bare arch means
arch-rolling, and a bare windows
means windows-11-25h2. Pin the full name when the release
matters, for example in test harnesses.
| Image | Source and how to get it |
|---|---|
ubuntu = ubuntu-24.04 |
Official Ubuntu 24.04 cloud image. image pull (automatic on first create) or image build. Pin a published build with ubuntu-24.04-YYYYMMDD (pull only). |
ubuntu-<release> |
Any release on cloud-images.ubuntu.com, e.g. 22.04 or 26.04. image build ubuntu-22.04, or image pull if published. |
ubuntu-x86apps = ubuntu-24.04-x86apps |
Ubuntu 24.04 that also runs x86_64 and i386 Linux programs, through FEX translation. image pull (automatic on first create; built locally, ~8 min, only if the download fails) or image build ubuntu-x86apps. Also 22.04: ubuntu-22.04-x86apps (x86apps is built for 22.04 and 24.04 only). |
arch = arch-rolling |
Arch Linux ARM (a community port of Arch) with XFCE and Chromium; install packages with sudo pacman -Syu --noconfirm <pkg>. image pull (automatic on first create; built locally in an Ubuntu helper VM, ~6 min, only if the download fails) or image build arch (needs the Ubuntu image, fetched if missing). Pin a published build with arch-rolling-YYYYMMDD (pull only). |
arch-x86apps = arch-rolling-x86apps |
Arch Linux ARM that also runs x86_64 and i386 Linux programs, through FEX translation. image pull (automatic on first create; built locally, ~10 min, only if the download fails) or image build arch-x86apps. Pin a published build with arch-rolling-x86apps-YYYYMMDD (pull only). |
windows-11-25h2 |
Windows 11 25H2 (Home/Pro), 7.3 GB ISO from Microsoft. image build windows. |
windows-11-24h2, windows-11-23h2 |
Earlier Windows 11 releases. image build windows-11-23h2. |
windows-<name> |
Your own Windows 11 ARM64 Home/Pro ISO. image build windows-<name> --iso <path>. |
Only ARM64 Windows runs at native speed on Apple Silicon, and Windows 10's ARM64 build hangs at boot, so Windows 11 is the minimum. Enterprise, LTSC and evaluation ISOs aren't supported. Windows runs unactivated (a watermark, nothing else).
Images are clean installs, like a customer's new PC: Windows has no Visual C++
redistributable, no .NET beyond the built-in Framework 4.8.1, and no PowerShell 7. If a
program fails with a missing VCRUNTIME140.dll, its installer is
missing a dependency. Each image records what it is:
$ agentpc image info windows
{
"os": "windows",
"version": "Windows 11 Pro 25H2 (build 26200.6584)",
"arch": "arm64",
"built": "20260927",
"desktop_server": "cua-driver 0.30.3",
…
}
How it works
- Hypervisor. VMs run in QEMU on Apple's Hypervisor.framework, natively on Apple Silicon.
- Instant start. After building or downloading an image, agentpc boots it once, waits until the desktop and its control server are running, and saves the VM's memory. New VMs resume from that state instead of booting: ~1 s / ~4 s instead of ~14 s / ~25 s.
- Checkpoints. A checkpoint pauses the VM for a few seconds, writes its memory to a file and clones its disk with an APFS copy-on-write clone.
- VMs from a checkpoint.
create_vmwithfrom_checkpoint(CLI--from) clones a checkpoint's disk into a new, independent VM and boots it cold; agentpc first deletes its own job records in that guest, so the new VM starts with none. Prepare a VM once and checkpoint it:restore_vmper task is fastest (same VM),from_checkpointgives independent copies. - Snapshots stay local. A memory snapshot depends on the Mac's chip and QEMU version, so only the disk is published; the snapshot is recaptured after each pull (about a minute).
- Image distribution. Ubuntu and Arch images are OCI artifacts on GitHub Container Registry: a compressed qcow2 split into 64 MB parts, downloaded in parallel and checksum-verified. A pull checks free disk space first; an interrupted one keeps its verified parts, and pulling again resumes from them. Every layer and the image config are checked against their manifest digest and size, and the joined disk must pass
qemu-img checkbefore it replaces the current image. - Dated image tags. An
image pushupdates rolling tags but preserves an existing…-YYYYMMDDtag. A refreshed rolling image can therefore differ from the dated build. Publishers on different machines must serialize pushes for a new date unless the registry enforces immutable tags. - Pinned downloads. What an image build fetches is pinned and verified: FEX by tag and commit, the Ubuntu and Arch x86 root filesystems and cua-driver's installers and binaries by SHA-256, the Arch Linux ARM tarball by its signature, and Chrome from Google's signed apt repository. Builds and snapshots check that the guest runs the pinned cua-driver.
- Agent-ready guests. Each snapshot capture turns off what interrupts unattended work (SmartScreen, updates, first-run pop-ups, Ubuntu's background apt jobs, Arch's pacman timers) and installs Chrome on Ubuntu.
- Arch build. A clone of the Ubuntu image installs the Arch Linux ARM tarball onto a blank second disk (systemd-boot, XFCE, Chromium, cua-driver); that disk becomes the image. The verified tarball is cached in
~/.agentpc/cache/alarmfor the next build. - x86apps build. FEX (pinned by tag and commit) is built from source as a static-pie, with a patch so x86 containers work, plus an x86 root filesystem: Ubuntu's as a squashfs the kernel mounts at boot, Arch Linux's unpacked so
fex-pacmancan add to it. QEMU for these VMs turns on the CPU's TSO mode (macOS 15+); agentpc tells FEX after each boot whether it got it.
Networking
Each VM sits behind QEMU's user-mode NAT: VMs are isolated from each other but share the Mac's network, so a VPN on the Mac applies to their outbound traffic.
| To reach | Do this |
|---|---|
| A VM server from the Mac | agentpc forward <name> <guest-port> (MCP: forward_port), then connect to 127.0.0.1:<host-port>. Works for servers bound to the guest's own 127.0.0.1; the Windows firewall doesn't apply. For a UDP server add --udp (MCP: protocol: "udp"); it must listen on 0.0.0.0, and on Windows needs a firewall rule. |
| The Mac from a VM | 10.0.2.2 is the Mac. A dev server on 127.0.0.1 or 0.0.0.0 is at 10.0.2.2:<port>. |
| VM to VM | Forward VM B's port to the Mac, then from VM A connect to 10.0.2.2:<host-port>. For UDP, forward with protocol: "udp" and have B's server listen on 0.0.0.0. |
| Through a corporate proxy | Guests inherit no proxy. Set HTTP_PROXY/HTTPS_PROXY in the guest and import your root CA (Import-Certificate on Windows, update-ca-certificates on Ubuntu, sudo trust anchor --store <cert> on Arch). |
Offline VMs (--offline / offline: true)
can't reach the internet or 10.0.2.2, but TCP ports you forward from
the Mac still reach them. UDP forwards don't work on them.
Configuration
| Variable | Description |
|---|---|
AGENTPC_HOME | Where images, VMs, keys and caches live. Default ~/.agentpc. |
AGENTPC_IMAGE_REPO | Package for image pull/push. Default ghcr.io/pawanpaudel93/agentpc. |
WIN_ISO | Windows ISO used by image build windows-… without --iso. |
AGENTPC_KEEP_RUNNING | Set to 1 to keep VMs running when an MCP session ends. |
Each VM gets its own ports on 127.0.0.1, derived from its slot number n:
| Port | Use |
|---|---|
47000 + n | SSH |
47200 + n | noVNC WebSocket, for the viewer |
47300 + n | VNC |
8100 | Browser viewer, shared by all VMs |
Guest tips
Windows: GUI installers return immediately
Run them silently and wait for the process, then check its exit code:
Start-Process installer.exe -ArgumentList '/S' -Wait -PassThru
Windows Update is disabled
So updates never interrupt a task. This also blocks DISM /online
and Add-WindowsCapability. Re-enable it temporarily:
Set-Service wuauserv -StartupType Manual; Start-Service wuauserv
# … Add-WindowsCapability / DISM …
Stop-Service wuauserv; Set-Service wuauserv -StartupType Disabled
Windows: Defender is on
Only SmartScreen is off. Defender may quarantine a fresh or unsigned test binary, so exclude your work directory:
Add-MpPreference -ExclusionPath C:\work
Windows: x64 apps run through emulation
The guest is Windows 11 ARM64. x64 and x86 programs (installers, desktop apps, CLIs) run through Windows' built-in Prism emulation, roughly 2–4× slower than native. x64 drivers, kernel-mode software and anti-cheat don't run. Prefer an ARM64 build when one exists.
Arch guest tips
- Packages:
sudo pacman -Syu --noconfirm <pkg>(Arch doesn't support partial upgrades). The first-Syumay upgrade the whole system, so giverun_commanda longertimeoutorbackground: true; after a kernel upgrade, reboot (start_vm) before loading new modules. /tmpis a tmpfs, cleared at every boot (unlike Ubuntu's); keep files elsewhere.
x86_64 Linux programs
The Ubuntu and Arch guests are arm64. Create a VM from ubuntu-x86apps
or arch-x86apps (create_vm with
version: "x86apps") and x86_64 and i386
programs run through FEX, which translates each one to arm64:
about 2× slower, JIT runtimes such as Node 6–7×, and much faster from the second start on
thanks to FEX's code cache. On macOS 15 or later the VM's CPUs also run in TSO mode, x86's memory
ordering, which makes multithreaded x86 code up to ~40% faster; list_vms
(agentpc list --json) shows it as x86_tso:
hardware or emulated. Go programs work (the image sets
GODEBUG=asyncpreemptoff=1 for them). x86 Electron and Chromium apps need
--no-sandbox. On Ubuntu a missing x86 library installs with
sudo apt install libfoo:amd64 (or an amd64 .deb:
sudo apt install ./app_amd64.deb, whose install scripts see an x86_64 machine); on Arch (no multiarch) x86 programs
use the image's x86 Arch Linux tree, and sudo fex-pacman -Sy --noconfirm --needed <pkg>
installs more x86 packages into it. x86 systemd services run too, hardened ones included: for a unit
whose ExecStart is an x86 program, a generator relaxes
MemoryDenyWriteExecute= and LockPersonality= (they stop FEX, as
any JIT); a unit that runs its x86 program through a script needs
sudo fex-unit <unit> (else it dies with a SIGSEGV inside FEX). An installer that refuses non-x86_64
(uname -m) runs unmodified under the x86 bash:
sudo FEXBash ./install.sh; for a paste block
(curl … | sudo bash -s), start FEXBash and paste it there.
x86 containers work too:
docker run --platform linux/amd64 <image> (install Docker first:
sudo apt install docker.io on Ubuntu, sudo pacman -Syu --noconfirm docker && sudo systemctl start docker on Arch). x86 kernel modules don't run: it's translation, not an x86 machine.
Hardware limits
Guests have a fixed 1280×800 display, a 2D-only GPU (no 3D acceleration; WebGL is software-rendered or unavailable) and no audio device.
Troubleshooting
| Symptom | Try |
|---|---|
| Something's off with the setup | agentpc doctor |
| Can't tell what the VM is doing | agentpc screenshot <name>, or open the viewer URL from agentpc info <name>. |
| VM won't boot | Read qemu.log and serial.log in ~/.agentpc/instances/<name>/ (MCP: read_vm_log). |
| VM is in a bad state | agentpc reset <name> |
| SSH dropped after a reboot | agentpc start <name> waits until the desktop is ready again. |
image build/pull/rm refuses | VMs still use that image; agentpc rm them first. Build and rm also refuse while a running build uses the image (an Arch build runs in a clone of the Ubuntu image), and rm while a pull or snapshot of it runs: try again when it finishes. A pinned …-YYYYMMDD image can only be pulled. |
| A build or snapshot says the guest runs another cua-driver | The image came from a different agentpc version: agentpc image build <image>. |
agentpc update can't write to its directory | sudo agentpc update, or reinstall there with AGENTPC_INSTALL_DIR=<dir>. |
| Running low on disk | agentpc clean deletes what can be downloaded again. |
Security
- Everything listens on
127.0.0.1only. - Before handing out a viewer link, agentpc authenticates the local viewer with a fresh HMAC-SHA256 challenge. The private identity key is not returned over HTTP; a recorded response cannot authenticate a different challenge.
- The desktop-control servers inside VMs are unauthenticated; any process on your Mac can reach them.
- Each VM has its own VNC password. The viewer URL from
agentpc infocarries it in the URL fragment, so the browser viewer connects without a prompt.--openandopen_in_browser: trueopen that same local viewer. Treat these links as credentials: do not share them, include them in logs, or capture the address bar in screenshots; browsers can retain visited URLs in history. - Guests use the fixed login
agent/agentfor the desktop and sudo; SSH takes only agentpc's key. Windows VMs have UAC prompts, SmartScreen and Windows Update turned off. - VMs can reach the internet and your Mac through
10.0.2.2. Use--offlinefor untrusted software. - Treat VMs as throwaway sandboxes, not a place for secrets.
Uninstall
$ agentpc uninstall # asks first; -y skips the prompt
This stops all VMs, removes the MCP server from every agent, and deletes
~/.agentpc (--keep-data keeps it) and the
binary. It leaves shared things alone and lists them: the PATH line,
QEMU, and the Claude plugin.