
agentpc
io.github.pawanpaudel93Published by GitHub account pawanpaudel93v0.1.12Updated Oct 24, 2026
Instant, resettable Windows, Ubuntu and Arch Linux ARM desktop VMs for AI agents on Apple Silicon.
Overview
Runs instant, resettable Windows, Ubuntu and Arch Linux ARM desktop VMs on an Apple Silicon Mac and lets an AI agent create, drive, screenshot and reset them.
- What you can do
- Create, list, start, stop, reset and delete local desktop VMs, including new VMs cloned from a checkpoint
- Save and restore checkpoints of a VM's disk and memory, and delete individual checkpoints
- Run PowerShell or bash commands in a guest, in the foreground or as background jobs, then check status, list jobs and stop them
- Take PNG screenshots and drive the guest desktop through the bundled desktop-control tools
- Copy files and folders between the Mac and a VM, forward TCP or UDP ports, and wait for a service to come up
- When to use it
- Useful when an agent needs a real, disposable desktop or clean machine to try install scripts, click through GUI apps, or test software without touching the host. Good for repeatable experiments where resetting to a fresh state in seconds matters.
- Requirements
- Apple Silicon Mac (M1 or later) on a macOS version QEMU supports, with QEMU from Homebrew; the installer can add Homebrew and QEMU. Roughly 4 GB RAM per Ubuntu or Arch VM and 8 GB per Windows VM, plus about 10 GB disk per Linux image and 30 GB per Windows image. Windows images must be built locally from a Microsoft ISO. Runs as a local stdio process.
Installation
In SourceWeft
- Open agentpc in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
agentpc
[License: MIT] [Platform: macOS on Apple Silicon] [MCP server]
Instant, resettable Windows, Ubuntu and Arch Linux ARM desktops for AI agents, on your Mac.
Website: https://agentpc.pawanpaudel.com.np
agentpc gives AI agents (Claude Code, Claude Desktop, Codex, Cursor, Gemini CLI, VS Code, or any MCP client) real desktop computers to work in: create a VM in seconds, let the agent click, type, take screenshots and run commands, then reset it to a clean state. It is a single Rust binary that runs VMs with QEMU on Apple's hypervisor and serves them to agents over MCP.
Contents
- Features
- Requirements
- Installation
- Quick start
- Using it with AI agents
- CLI reference
- Images
- Configuration
- How it works
- Troubleshooting & guest tips
- Uninstalling
- Security
- Development
- License
Features
- Instant VMs. New VMs resume from a saved snapshot of a running desktop: ready in
~1 s (Ubuntu, Arch) or ~4 s (Windows).
resetreturns a VM to a clean state just as fast. - Checkpoints. Save a running VM (disk and memory) before a risky step and return to that exact state in seconds.
- Real desktops. Windows 11 (ARM), Ubuntu 24.04 or another release (XFCE), and Arch Linux ARM (XFCE), each with a desktop-control server agents can drive: cua-driver on all of them.
- One MCP server for everything. Agents create, drive, screenshot and delete VMs
themselves. Works with any MCP client;
agentpc mcp-installsets up the popular ones. - Shell and screen access. Run PowerShell or bash over SSH; take PNG screenshots straight from the hypervisor in ~40 ms, even while a guest is booting or hung.
- Files and ports. Copy files and folders between your Mac and a VM, and reach servers running inside a VM from your Mac.
- Agent-ready guests. 1280x800 desktops with a browser (Edge on Windows, Chrome on Ubuntu, Chromium on Arch) and the pop-ups, update restarts and background jobs that interrupt unattended work turned off.
- Watch along. Every VM has a browser viewer, so you can see what the agent is doing. Use
agentpc create ubuntu --openor MCPopen_in_browser: trueto open it in the Mac’s default browser after readiness; neither opens a tab by default. - x86 apps. x64 Windows apps run through Prism;
ubuntu-x86apps/arch-x86appsrun x86_64 Linux programs and amd64 containers through FEX. - Any version, side by side. Run Ubuntu 22.04, 24.04 and 26.04, or several Windows 11 releases, at the same time. Each image records its OS version, source and build date.
- Local and private. Everything runs on your Mac and listens on
127.0.0.1only.
Requirements
Installation
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 (
agentpc mcp-install), - checks everything with
agentpc doctor.
To upgrade later, run agentpc update (or agentpc update --check to just look); rerunning the
installer works too. Installer options:
To build from source instead, see Development.
Quick start
Ubuntu:
Arch Linux ARM:
Windows: Microsoft's license doesn't allow redistributing Windows images, so each Mac builds its own once. agentpc downloads the official Windows 11 ARM64 ISO from Microsoft (7.3 GB, checksum-verified) unless you already have one:
Then ask your agent something like:
- "Create an Ubuntu VM, open a terminal and run
uname -a." - "Reset ubuntu-1 and check that my install script works on a clean machine."
- "Open Notepad on windows-1, type a short note and show me a screenshot."
To watch a VM yourself, open the viewer URL printed by agentpc info <name>.
Using it with AI agents
agentpc is an MCP server (agentpc mcp, stdio). One server handles every VM.
Claude plugin
In Claude Code, install the agentpc plugin. It bundles the MCP server with a skill that teaches Claude when and how to use the VMs:
The plugin runs the installed agentpc binary, so install that first
(see Installation). When the plugin is installed it already registers the MCP
server for Claude Code, so agentpc mcp-install skips Claude Code to avoid a duplicate.
Other agents
Register it with every supported agent that's installed (the installer does this):
Supported: Claude Code, Claude Desktop, Codex, Cursor, Gemini CLI and VS Code (restart Claude
Desktop after registering). Updating an existing JSON mcpServers.agentpc or Codex
[mcp_servers.agentpc] entry preserves custom environment/options while refreshing the
managed command and arguments, and keeps the comments and blank lines around them. Config
is written through a private temporary file. Invalid config is refused, not replaced;
multiline TOML values are edited as complete values. For any other MCP client, add:
This repository also contains project-level configs (.mcp.json, .codex/config.toml,
.cursor/mcp.json, .gemini/settings.json, .vscode/mcp.json), so agents opened in a clone
pick the server up automatically.
Tools
If a desktop-tool reply starts with a reconnect note (the VM or its driver restarted), earlier
snapshot ids and browser sessions are gone: take a new snapshot and run browser_prepare again.
VMs an MCP session created, started, reset or restored are stopped (never deleted) when the
session ends, unless AGENTPC_KEEP_RUNNING=1. If the session's server was killed instead, the
next MCP server to start stops them; list_vms marks such VMs owner_running: false, and
create_vm with the same name and image hands one back to the session that asks. Session shutdown is
bounded at about 45 s per VM (lock wait, ACPI shutdown, then a forced quit); a VM another
session has taken over is left alone.
Command results and job output
run_command and get_job_status return structuredContent that matches the outputSchema they
declare (schema_version 1), next to the readable text scripts have always parsed. The text is the
legacy exit code: N / STATE: ... form in a single block, not a JSON copy, so clients that join text
blocks see no extra output. Read the typed fields and isError; the full contract is in
AGENTS.md.
run_command:stateisexited,timed_out,not_started,connection_lost,startedorcancelled. It carriesrequest_cancelled,exit_code,stdout,stderrwith byte counts and truncation flags,termination_confirmed,effect_unknown,recovery_action, anexecution_id(null only when the call failed before one was issued, such as an unknown VM) and, when you need a handle, ajob_id. Every nonzero exit, timeout, failed start or lost connection is a tool error, even a timed-out command whose own exit code is known to be 0.- Timeouts: at
timeout, agentpc attempts to stop the command and what it started and keeps the partial stdout and stderr.termination_confirmed: truemeans it verified that none of the processes it identified is left: on Linux the command's transient systemd user scope when the guest's user manager is available, the processes marked with its execution id and their descendants (all that is checked without a user manager), and its verified root; on Windows its verified process tree, best effort. It is not a sandbox guarantee. System services, other systemd units and Windows services, scheduled tasks and WMI-created processes are not covered. A command whose exit code the VM recorded but whose run had not ended by the timeout (a child it left may have held its output, or it ended right at the deadline) returns that exit code withtimed_out: true, after cleanup verified that none of the processes it identified remains. If it can't confirm the stop (termination_confirmed: false), or the connection was lost before the command's end was known (connection_lostwitheffect_unknown: true),effect_unknownis true and thejob_idworks withget_job_statusandstop_job; aconnection_lostwitheffect_unknown: falsecarries the recordedexit_codeand nojob_id; commands are never retried automatically, and onlyrecovery_action: retrymeans one provably never ran. The reply follows a timeout within a few seconds usually, and about 50 seconds at most. - Cancellation: a foreground
run_commandis stopped in the VM, as at a timeout, when its request is cancelled (notifications/cancelled), the client disconnects or the MCP session ends. The result hasrequest_cancelled: trueand is a tool error:cancelledwithtermination_confirmed: truewhen the stop was verified,exitedwith the command's code when it had already finished,not_startedwhen it never began (no retry is suggested), orcancelledwithtermination_confirmed: false,effect_unknown: trueandrecovery_action: stop_jobwhen the stop could not be verified. A client that cancelled usually never receives that reply: find the run again withlist_jobs, thenget_job_statusreportsstoppedwithstop_reason: request_cancelled(ornot_started). A request cancelled before anything was sent starts nothing. A background start is detached on purpose: cancelling its request, disconnecting or ending the session does not stop the job; usestop_job.AGENTPC_KEEP_RUNNING=1keeps the VMs, not the foreground commands, and a hard kill of the MCP server cleans up nothing (the job records stay in the VM). - Foreground exit codes are the low 8 bits SSH reports (Windows
exit -1reads 255). A Linux foreground command is limited to 92 KiB (94,208 UTF-8 bytes) of text, checked before anything is sent (a bigger one isnot_started, with no retry); for a bigger script,upload_fileit and run the file. get_job_status: withoutwait_secondsorcursorit answers at once with the lasttail_lineslines (at most 16 KiB) and anext_cursor. Withwait_secondsit waits for the job to leaverunning(with acursor, for new output) and returns the current state withwait_timed_out: trueif nothing happened; a wait never stops the job. Acursor(anext_cursor, or"start") returns at most 16 KiB from that byte position and advances by exactly what it returned, so output is neither repeated nor skipped; UTF-8 characters are never split. A cursor that no longer matches the log (VM reset or restored, guest reboot, log replaced, shortened or rewritten) is reset and said so (cursor_reset,cursor_reset_reason); that detection is best effort.missingmeans nothing has recorded itself under the id yet, which doesn't prove it never started. An unreachable VM is an error, never reported asended.list_jobs: read-only, metadata only (job_id,kind,state,exit_code,stop_reason,log_available,records,recorded_at,finished_at, anoteon an unresolved entry), newest id first,limit1 to 100 (default 20). Whenhas_moreis true, passnext_cursorascursor; pages continue below the last job shown within the VM as the first page saw it, so jobs created meanwhile do not shift them. A cursor from before a VM reset, restore or recreation iscursor_stale: the VM's generation changed and its records may differ from what the earlier pages listed (a restored checkpoint can keep some), so the listing cannot safely continue; call again without a cursor. The listing is best effort, not an immutable history: records age out, and a huge job directory keeps only its first entries (scan_truncated), so jobs may be missing. Aqueued,missingorunknownentry is unresolved, not proof the command never started. Cancelling the call abandons only the listing.wait_for_service: polls only the VM's own IPv4127.0.0.1(never another host, a URL or a proxy).protocol: "tcp"(default) is ready when a connection is accepted;"http"is ready when oneGET path(/by default, a path not a URL; no credentials in it, because it is echoed in the result and visible in the VM's process list) returnsexpected_status(default 200).pathandexpected_statusare HTTP-only and refused withtcp. Redirects are not followed, and no response body, header or guest text is returned: the result hasstate(ready,timed_out,job_failed,cancelled,error), the lasttcp/http_outcome(status_matched,redirect,status_mismatched,no_response,malformed) /http_status,attempts,waited_msanderror_code(such asprobe_unsupportedwhen the guest's bash has no/dev/tcpor it has notimeoutcommand). Anything butreadyis a tool error, andtimed_outkeeps the last observation.timeout_secondsbounds the waiting, not the wall clock: a call can run about 5 s past it. Withjob_idthe wait ends early (job_failed) only for a proven failure: a nonzero exit, a stopped job or one that never started; a job that exited 0 (a server may outlive its wrapper), is queued, running, missing or unreadable is not failure. Ready describes the endpoint, not a process: nothing checks who owns the port, so it does not prove the job started it. Waiting never stops the service or the job, and cancelling it only stops probing, but each probe makes short-lived connections (and one GET), so it can consume a one-shot listener.inspect_desktopchecks the driver's ownreadOnlyHintbefore each dispatch and refuses an unmarked, unknown or not read-only tool before dispatching it, with nothing run (looking up the annotations does ask the VM's driver). The marking is the driver's claim, a guard against mistakes rather than a guarantee. Compact observation:get_window_statewithinclude_screenshot: falsereturns the element tree without a screenshot, and itsqueryargument narrows what comes back.
Approval prompts
Every desktop action goes through use_desktop_tool, which is marked destructive, so clients that
confirm tool calls ask before each click or keystroke. inspect_desktop is marked read-only and only
runs tools the driver marks read-only, so clients can auto-approve looking while still confirming
acting. To approve agentpc's tools up front:
That approves every agentpc tool, including upload_file and download_file, which read and write
files on your Mac. The VMs themselves are throwaway: reset_vm undoes anything done inside one.
AGENTS.md has usage tips for agents.
CLI reference
VMs
Commands that act on VMs take several names (agentpc stop a b), check them all before
doing anything, and carry on past a failure (exit status 1 if any failed). Every command has
--help.
Image commands
Setup
Images
An image is a read-only disk with the OS, desktop and agent tools installed. Every VM is a copy-on-write clone of an image, so a VM starts from a clean install and costs only a few MB.
Images are named <os>-<version>, and several can be installed side by side; each VM
remembers which one it came from. A bare ubuntu means ubuntu-24.04, a bare arch means
arch-rolling, and a bare windows (or windows-11) means windows-11-25h2. To save a 12-minute build, create and
image info fall back to your newest installed Windows 11 image if 25H2 isn't built. Pin the
full name when the release matters, e.g. in test harnesses.
Only ARM64 Windows runs at native speed on Apple Silicon, so x64-only releases aren't offered,
and Windows 10's ARM64 build hangs at boot on Apple Silicon, so Windows 11 is the minimum.
The unattended install uses the Home/Pro setup key, so Enterprise and LTSC ISOs aren't
supported. An ISO in ~/Downloads is used when its file name shows the release being built;
--iso with a release name must match it too (a 24H2 ISO can't become windows-11-25h2).
Windows runs unactivated (a watermark, nothing else); activate it with your own key if you
need to.
Images are clean installs, like a customer's new PC: Windows has no Visual C++ redistributable,
no .NET (only the built-in .NET Framework 4.8.1) and no PowerShell 7. A program that runs on
your machine but fails in a VM with a missing VCRUNTIME140.dll or similar is missing a
dependency its installer should provide. Microsoft's evaluation ISOs aren't offered: they install already expired and shut
down every hour.
Microsoft serves only its current ARM64 ISOs; the older ones download from archive mirrors
(archive.org, bobpony.com). Every ISO is checked against a pinned SHA-256, so a mirror can't
substitute a modified file, and kept in ~/.agentpc/cache. All are en-us; for another
language, download it yourself and pass --iso.
Each image records what it is (agentpc image info <image>):
Published images live in one package, ghcr.io/pawanpaudel93/agentpc, tagged by image
name. Windows images can't be redistributed:
A pinned build is download-only: image build refuses it, and a create whose download fails
doesn't fall back to building today's instead. Short names work too (ubuntu-x86apps-YYYYMMDD
is ubuntu-24.04-x86apps-YYYYMMDD). A push updates rolling tags but leaves an
existing dated tag untouched, even after recapturing the local image. The dated tag
still selects its original publication, not necessarily the current rolling image.
Publishers on different machines must serialize pushes for a new date: without
registry-side immutable tags, a tag check and creation are not atomic.
Configuration
Each VM gets its own ports on 127.0.0.1, derived from its slot number n (an existing VM
moves to its new ports the next time it starts):
The guest login is agent / agent for the desktop and sudo; SSH takes only agentpc's key
(password logins are off). Each VM also has its own VNC password (see
Security).
How it works
- Hypervisor. VMs run in QEMU with Apple's Hypervisor.framework (HVF), natively on Apple Silicon, with nothing else in between.
- 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 saved state instead of booting (~1 s / ~4 s instead of ~15 s / ~25 s). A
startafterstopis a normal boot;resetresumes a fresh copy again. - Checkpoints. A checkpoint pauses the VM for a few seconds, writes its memory to a file
and clones its disk (an APFS copy-on-write clone, so it costs nothing until the VM writes
more). Restoring resumes from them like a new VM does. Each checkpoint of a running VM
takes disk space about equal to the memory in use (3–4 GB for Windows);
agentpc checkpoint <name> <label> --deleteremoves one, and deleting the VM removes all of them. - VMs from a checkpoint.
create --from <vm>/<label>(MCPfrom_checkpoint) clones the checkpoint's disk and firmware vars (APFS clones) into a new VM, under the source VM's lock and the image lock, and boots it cold; the new disk is backed by the image only. Before it returns, agentpc deletes its own job records in the guest (~/agentpc-bg; on Windows also itsagentpc-bg-<id>scheduled tasks), solist_jobsstarts empty. A checkpoint of a running VM first has the guest flush its writes, so the copied disk holds them. - 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). Each snapshot records the QEMU machine type, so it still resumes after a QEMU upgrade.
- Robustness.
createchecks free disk and RAM up front andcheckpointchecks disk; restore is atomic (a failed one leaves the VM as it was) and resumes a VM that was left paused; operations on one VM are serialized, and a stale pid file from a crash is detected rather than trusted. The guest clock follows the Mac's time zone. SSH keepalives hold long calls open, a desktop tool call gives up after 120 s, and a viewer that won't start no longer fails a VM start. The browser viewer (noVNC) is downloaded against a pinned checksum. - 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. - 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.
- Windows build. agentpc writes a small setup disk next to the ISO: an unattended-install
answer file (adapted from dockur/windows-arm), Red
Hat's ARM64 virtio drivers, and a first-logon script that installs OpenSSH and cua-driver (telemetry off).
Windows Setup then runs in QEMU with no clicks; if that script fails, the build stops at once
(see
C:\OEM\failed.txtandC:\OEM\setup.login the guest) instead of timing out. - Ubuntu build. The official cloud image is provisioned with cloud-init: XFCE on X11,
auto-login, and cua-driver (pinned, so tool names match these docs; telemetry off). cloud-init is then disabled so clones don't re-provision. To opt in to cua-driver's telemetry, run
cua-driver telemetry enablein the VM. - Arch build. A clone of the Ubuntu image gets a blank second disk, and a script installs
the Arch Linux ARM tarball onto it: systemd-boot, XFCE on X11 with auto-login, Chromium and
the same pinned cua-driver. That disk becomes the image. The verified tarball is kept in
~/.agentpc/cache/alarmfor the next build (agentpc cleanremoves it). - x86apps build. On
ubuntu-x86appsandarch-x86apps,guests/<os>/x86apps.shbuilds FEX (tag and commit pinned there) from source as a static-pie withguests/ubuntu/fex.patch(so x86 containers work) and installs an x86 root filesystem: Ubuntu's as a squashfs the kernel mounts read-only at boot (not FEX through FUSE, which a sandboxed service can't), Arch Linux's unpacked sofex-pacmancan add packages to it. QEMU for these VMs loadssrc/hvf_tso.c, which turns on the CPU's TSO mode; agentpc checks the result after each boot and tells FEX, which falls back to emulating x86 memory ordering when TSO is off. - Agent-ready guests. Each time a snapshot is captured, a prepare script turns off what interrupts unattended work (Windows SmartScreen, updates, first-run and tip pop-ups; Ubuntu's background apt jobs; Arch's pacman timers) and installs Google Chrome on Ubuntu for cua-driver's browser tools (Arch's image ships Chromium).
Troubleshooting & guest tips
- Check the setup:
agentpc doctor. - See the screen:
agentpc screenshot <name>, or open the viewer URL fromagentpc info <name>. - Logs for each VM are in
~/.agentpc/instances/<name>/:qemu.log(QEMU errors) andserial.log(guest console). - A VM is in a bad state:
agentpc reset <name>. image build/pull/rmrefuses: VMs still depend on that image;agentpc rmthem 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…-YYYYMMDDimage can only be pulled.- An image build or snapshot says the guest runs another cua-driver: the image was built
by a different agentpc version; rebuild it with
agentpc image build <image>. agentpc updatecan't write to its directory (e.g. a root-owned/usr/local/bin): runsudo agentpc update, or reinstall there withAGENTPC_INSTALL_DIR=<dir>.
Networking
Each VM sits behind QEMU's user-mode NAT, so VMs are isolated from each other but share the Mac's network (a VPN or proxy configured on the Mac applies to a VM's outbound traffic).
- Reach a server in a VM from the Mac:
agentpc forward <name> <guest-port> [host-port](MCP:forward_port), then connect to127.0.0.1:<host-port>. It tunnels over SSH, so it reaches a server bound to the guest's own127.0.0.1and the Windows firewall doesn't apply. A forward lasts until the VM stops or you remove it (--rm <host-port>/delete_forward);--list(MCP:list_forwards) shows a VM's forwards. - UDP servers (games, DNS, QUIC, relays): add
--udp(MCP:protocol: "udp"). A UDP forward is a QEMU host forward rather than an SSH tunnel, so it reaches the guest's network address (10.0.2.15): the server must listen on0.0.0.0, not127.0.0.1, and on Windows it needs a firewall rule. It's dropped on stop, restore and reset like a TCP forward, and isn't available on offline VMs. - Reach the Mac from a guest:
10.0.2.2is the Mac host — the NAT maps it to the Mac's loopback, so a dev server listening on127.0.0.1or0.0.0.0is reachable at10.0.2.2:<port>from inside the VM. - VM to VM: there's no direct route. Forward the server VM's port to the Mac
(
forward_port(B, guest_port, host_port)), then from the other VM connect to10.0.2.2:<host_port>. For UDP passprotocol: "udp"and have B's server listen on0.0.0.0. - Offline VMs (
--offline/offline: true) can't reach10.0.2.2or the internet, but TCP ports you forward from the Mac still reach them. UDP forwards don't work there: the offline network drops every UDP datagram the guest sends, replies included. - Corporate proxy / CA: a guest inherits no proxy settings from the Mac. Set
HTTP_PROXYandHTTPS_PROXYinside the guest, and import your corporate root CA withImport-Certificate(Windows),update-ca-certificates(Ubuntu) orsudo trust anchor --store <cert>(Arch).
Guest reboots
Rebooting a guest (a Windows Update install, some installers) drops the SSH connection. Call
start_vm on the same VM — it waits until the desktop is ready again even when the VM is
already running — then rerun the command. If its reply was connection_lost with
effect_unknown: true, check what it did first with get_job_status and its job_id.
Windows guest tips
-
GUI installers return immediately. Run them silently and wait for the process:
Start-Process installer.exe -ArgumentList '/S' -Wait -PassThru(the switch varies:/S,/silent,/quiet), then check itsExitCode. Arun_commandprocess ends when the command returns, so start servers and GUI apps withbackground: true. -
Windows Update is disabled in the image (the
wuauservservice is stopped and set to Disabled, and theNoAutoUpdatepolicy is set) so updates never interrupt a task. This also blocks optional features that fetch from Windows Update — DISM/online(e.g. .NET 3.5) andAdd-WindowsCapability(RSAT, language packs; OpenSSH is already installed). To use one, re-enable it temporarily and set it back afterwards: -
Defender real-time protection is on. agentpc only disables SmartScreen, not Defender, so Defender may quarantine a freshly built or unsigned test binary. Exclude your work directory with
Add-MpPreference -ExclusionPath C:\work, or turn real-time monitoring off withSet-MpPreference -DisableRealtimeMonitoring $true(Tamper Protection may block the latter). -
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 a download offers one.
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. For x86_64 (and i386) Linux programs, create a VM from
the ubuntu-x86apps or arch-x86apps image (agentpc create ubuntu-x86apps, or create_vm
with version: "x86apps"). It adds FEX, which translates each x86 program
to arm64 as it runs; the kernel and desktop stay native. Run the program directly (./tool).
- Speed. Most code runs about 2× slower than native, JIT runtimes such as Node about
6–7×. On macOS 15 or later, agentpc also switches these VMs' CPUs to TSO, x86's
memory ordering, so FEX needn't emulate it: multithreaded code runs up to ~40% faster, and
native arm64 code isn't slowed.
agentpc list --json(list_vms) shows which a VM got asx86_tso:hardwareoremulated. FEX keeps translated code in~/.cache/fex-emu, so a program's second start is several times faster than its first. - Libraries. x86 programs find the common libraries (libc, libstdc++, GTK, ...) in an x86
tree the image ships (x86 Ubuntu or x86 Arch Linux). On Ubuntu, install anything else as the
amd64 package:
sudo apt install libfoo:amd64(the image has amd64 package sources set up), or an amd64.debwithsudo apt install ./app_amd64.deb; its install scripts (run by the native dpkg) see an x86_64 machine inuname -m,archanddpkg --print-architecture, so vendor packages that check pass. Installing an amd64 library can upgrade its arm64 twin, since both must be the same version. Arch has no multiarch, so onarch-x86appsx86 programs use FEX's x86 Arch Linux tree, andsudo fex-pacman -Sy --noconfirm --needed <pkg>installs more x86 packages into it (the x86pacman, run in a chroot, pinned to that tree's Arch Linux Archive date so nothing is partially upgraded). - Go programs crash under FEX unless
GODEBUG=asyncpreemptoff=1; the image sets it for x86 programs. - x86 Electron and Chromium apps (VS Code, Slack, Chrome, ...) abort at launch with a
zygote_hosterror: FEX can't create the namespaces Chromium's sandbox uses. Launch them with--no-sandbox(e.g.code --no-sandbox). - x86 containers work: install Docker or Podman (on Arch:
sudo pacman -Syu --noconfirm docker && sudo systemctl start docker) and rundocker run --platform linux/amd64 <image>. FEX runs them from the image's own x86 files. - x86 services run under systemd, as system users without a home too (FEX then keeps its
config and code cache in the unit's
StateDirectory=or a private/tmp/fex-emu-<uid>). A unit withMemoryDenyWriteExecute=orLockPersonality=would stop FEX, as it stops any JIT, so a systemd generator (/etc/systemd/system-generators/agentpc-fex) relaxes those two for every unit whoseExecStartis an x86 program; native services keep them, andsystemctl catshows the drop-in. A unit that runs its x86 program another way (a script) needssudo fex-unit <unit>(--undoremoves it); without it the service dies at start with a SIGSEGV inside FEX and an AArch64 core dump, which looks like an application crash. WithProtectSystem=strict, give the unit a writable directory (StateDirectory=orPrivateTmp=). - x86-only installers that check
uname -mrun unmodified under the x86 bash:sudo FEXBash ./install.sh. Itsuname,useradd,systemctland other tools then run as x86 programs, so the script sees an x86_64 machine. For a paste block (curl ... | sudo VAR=... bash -s -- args), startFEXBashand paste it there: the realsudois setuid and runs natively, so FEXBash puts its ownsudofirst onPATH, which has the real one start the command through FEXBash and keeps it x86. - Not covered: x86 kernel modules and drivers. It's translation, not an x86 machine.
Hardware limits
Guests have a fixed 1280x800 display, a 2D-only virtio GPU (no 3D/GPU acceleration; WebGL is software-rendered or unavailable), and no audio device.
Uninstalling
This stops all VMs, removes the MCP server from every agent mcp-install registered it with,
deletes ~/.agentpc (images, VMs, checkpoints and keys; --keep-data keeps them) and the
agentpc binary. It leaves shared things alone and lists them: the PATH line the installer
added (~/.local/bin is used by other tools too), QEMU (brew uninstall qemu if nothing else
needs it) and the Claude plugin (/plugin uninstall agentpc@agentpc).
To only reclaim disk space, agentpc clean deletes what can be downloaded again, and
agentpc image rm <image> deletes an image you no longer use.
Security
- Everything listens on
127.0.0.1only. - The desktop-control servers inside the VMs are unauthenticated; any process on your Mac can reach them.
- Each VM has its own VNC password (
vnc-pass, mode 0600, in its instance dir). The viewer URL fromagentpc info <name>carries it (&password=…) so the browser viewer connects without a prompt; a native VNC client (vnc://127.0.0.1:<port>) asks for it — copy it from that URL or read~/.agentpc/instances/<name>/vnc-pass. - Guests use the fixed login
agent/agentfor the desktop andsudo. SSH takes only agentpc's key, since every VM's SSH port is reachable from the other VMs and local users. ~/.agentpcis private to you (0700): it holds guest disks, RAM checkpoints and the SSH key.- The browser viewer link carries the VNC password after
#, which no request sends, and is only given out when the server on port 8100 is agentpc's own. Commands verify the viewer with a fresh HMAC-SHA256 challenge; the private identity key is never served over HTTP, and an observed response cannot authenticate a different challenge. - To keep agents unblocked, Windows VMs have UAC prompts, SmartScreen and Windows Update turned off. Don't use them for anything that needs those protections.
- VMs can reach the internet and, through its gateway
10.0.2.2, services on your Mac. Create a VM with--offline(offline: trueincreate_vm) to cut both off, e.g. for untrusted software; SSH, the viewer and forwarded ports keep working. - The MCP tools carry annotations:
list_vms,take_screenshot,list_desktop_tools,inspect_desktop,get_job_status,list_jobs,wait_for_service,list_forwardsandread_vm_logare read-only, and tools that discard or overwrite state (includingdownload_file, which writes to your Mac) are marked destructive, so clients can auto-approve or confirm accordingly. - Treat VMs as throwaway sandboxes, not as a place for secrets.
Development
The lifecycle stress suite requires an existing, current Ubuntu snapshot; it never downloads or builds images. It briefly holds an idle image lock to delay cloning, checks that queued start/delete calls wait for initialization, and verifies a one-worker MCP server remains responsive. It then races named creates, starts, stops and deletes and checks killed-session orphan recovery and graceful session shutdown. It uses only uniquely named task-owned VMs, deletes them afterward, and refuses to start when unrelated running orphan VMs could be reaped. Logs omit raw MCP responses and viewer credentials. CI checks its syntax; VM tests run locally on Apple Silicon.
Run the smoke test after changing guest scripts, the desktop driver or the MCP gateway (rebuild the affected images first). It checks that guests open apps without first-run dialogs, that the desktop tools read and type, and that the gateway explains bad arguments.
Guest provisioning files in guests/ are embedded into the binary. AGENTS.md
describes the code layout for contributors and coding agents.
Releasing (maintainers)
- On an up-to-date, clean
main, runscripts/release.sh X.Y.Z(needsghlogged in, Node fornpx, andjq). It sets the version everywhere (skipped whenCargo.tomlis already at X.Y.Z), runs the CI checks, buildsdist/(binary tarball, MCP bundleagentpc-X.Y.Z.mcpb, their.sha256files, a filled-inserver.jsonandNOTES.md, the release notes grouped from the Conventional Commit subjects since the last tag), then asks before it commitschore: release vX.Y.Z, tagsvX.Y.Z, pushesmainand the tag, and creates the GitHub Release.--dry-runstops after buildingdist/. - Publish the Linux images (
ubuntu,ubuntu-x86apps,archandarch-x86apps): logorasin with a token that can write packages (gh auth refresh -s write:packages, thengh auth token | oras login ghcr.io -u <user> --password-stdin), then for each image runagentpc image build <image>andagentpc image push <image>. A push uploads 64 MB parts, retries failures and links the package to this repo; make the package public once in its settings. - Publish to the MCP Registry:
brew install mcp-publisher,mcp-publisher login github, thenmcp-publisher publish dist/server.json.
License
MIT © 2026 Pawan Paudel
Source: README.md at commit 8194f49
Tools
0Version history
8- v0.1.12LatestOct 4, 2026
- v0.1.11Oct 2, 2026
- v0.1.10Sep 30, 2026
- v0.1.7Sep 30, 2026
- v0.1.4Sep 29, 2026
- v0.1.2Sep 27, 2026
- v0.1.1Sep 27, 2026
- v0.1.0Sep 27, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts