Repository navigation
Releases
v0.10.1
Fixes for Lima hosts reached over ssh, and for running the test suite in a terminal. Also adds an experimental OpenShell backend. No upgrade steps beyond the usual boxery upgrade-host.
Fixes
- Lima on a remote Mac with Node from fnm or nvm.
boxery newfailed with onlylimactl start … failed, because the Lima backend ran barenode, which isn't onPATHin the non-interactive ssh session the controller uses. Backend scripts now always use the host's own Node, the oneinitrecorded (#146, #158, fixes #143). - Lima on a remote Mac with Homebrew. Over non-interactive ssh,
limactlfrom/opt/homebrew/binwasn't found, andboxery newwrongly reportedno base image; run: boxery-host build-base. On macOS, backend calls (and the sshProxyCommand) now add/opt/homebrew/bin:/usr/local/binto the end ofPATH. If a backend can't tell whether the base exists, it now says why, instead of reporting that the base is missing (#157). - The Lima ssh port with
FORCE_COLORset. The free-port helper printed the port withconsole.log, which wraps it in colour codes whenFORCE_COLORis set. The port was then rejected, and a confined Lima start failed withno free port. This also madenpm test(and sonpm publish) fail when run in a terminal, since the test runner setsFORCE_COLORthere (#156).
New: OpenShell backend (experimental)
boxery can now drive headless sandboxes on an OpenShell gateway, where OpenShell's policy limits what each sandbox can read and reach on the network (#152, #153):
boxery setup local --backend openshell
boxery --host restricted new demo --headlessIt supports the shell, file, copy and background-job tools. Desktops, snapshots, forks, resize, pools and boxery grants aren't supported and are refused with an error. OpenShell manages credentials and network access itself. It has been tested on Linux only. See docs/openshell.md.
Upgrading
boxery upgrade-host, then update the controllers. The image layers haven't changed since 0.10.0, so desktop bases and existing VMs don't need a rebuild or a patch.
v0.10.0
This release requires a person to approve new VM access, adds GitHub Actions runners on pool VMs, and lets you see and patch VMs whose software is out of date. It also fixes ssh to VMs on remote hosts, which was broken in 0.9.0. Read "Upgrading" first.
Highlights
- New access needs a person.
boxery grant,agent-forward on,new --grant,fork --grants, pi's/vm grantandvm_grantall show what would be granted and ask for approval. The CLI reads the answer only from/dev/tty, defaults to No, and refuses to run without a terminal, so pipingyesdoesn't approve anything. Listing, revoking and re-applying existing grants don't ask. For cron, CI or pool setup, addGRANT_CONFIRM=offto a profile'sconfig(#138, details). - GitHub Actions runners on your own host. Each job runs in a fresh pool VM, which is reset to its clean image afterwards. The GitHub token stays on the host, and the VM only gets a single-use JIT config (#141, docs):
boxery new r1 --headless --layers github-runner && boxery pool add r1 boxery runners token < token.txt
boxery runners onceregisters one runner with your ownghlogin, from wherever you run it. The host never holds a GitHub credential (#145).- See which VMs are out of date, and patch them in place.
boxery lshas a GUEST column:current,outdated(older layers, built more than 30 days ago, or waiting for a reboot) orunknown.boxery patch NAME(or--all) runs the layers again inside a running VM:apt-get full-upgrade, the kernel,playwright-core, the pi and opencode CLIs, and node. It restarts the VM if needed. For pool VMs, it capturesNAME@boxery-cleanagain, so later leases start patched (#137).
Security
- Security updates in every VM, and MPTCP turned off. Every VM, desktop or headless, now runs
apt-get full-upgrade(kernel included) when it's built. Before, VMs kept whatever the cached Ubuntu image had. MPTCP is turned off (net.mptcp.enabled=0) because of CVE-2026-98432, which has no fixed Ubuntu 24.04 kernel yet (#136). - The LLM proxy drops guest OpenAI billing headers. A VM can no longer pick another org or project with
openai-organization/openai-project. Set them on the host withOPENAI_ORG_ID/OPENAI_PROJECT_IDinproxy.env(#147).
Fixes
- ssh to VMs on remote hosts. In 0.9.0, a controller set up with
boxery setup user@hostwrote aKnownHostsCommandthat ssh couldn't run, so every VM failed host key verification. Local hosts were fine. Existing profiles are rewritten the next time you run a command (#149). - Locks that hold on uutils coreutils. Ubuntu 26.04's default
mkdirisn't atomic under a race. As a result, concurrent grants or revokes could lose an entry, and concurrentnews could get the same network slot or port. Both now use anO_EXCLlock (#129, #134). - macOS:
initno longer fails intermittently withBootstrap failed: 5: Input/output errorwhile launchd is still removing the old job (#132). initrefuses aHOMEthat isn't the account's, so it can't install services launchd or systemd would never load. Shell tests can no longer replace the real proxy on macOS (#140).tokens.jsonis parsed again only when it changes, not on every proxied request (#147).
Other changes
e2e.shchecks first that grants can be approved. Without a terminal, it needsGRANT_CONFIRM=offin the profile and otherwise exits before creating a VM (#151).- Agent behaviour evals for the MCP server, under
evals/: whichvm_*tools an agent uses, and whether it follows instructions (#148). - Docs: a new README, tagline, hero diagram and promo video, and a research section that starts with hunk's test suite on macOS vs boxery VMs vs Docker (#128, #130, #131, #133, #135, #139, #142).
Upgrading
- Upgrade the host before the controllers (
boxery upgrade-host). - Scripts that run
boxery grantwithout a terminal now fail. Either have a person run them, or addGRANT_CONFIRM=offto that profile'sconfig. That setting turns off CLI confirmation for the profile, so use it only where an agent adding grants unprompted is acceptable. MCP and pi clients need a confirm dialog or elicitation to grant anything; pi's print mode can't approve. - Rebuild the desktop base, and patch or recreate existing VMs, to get the security updates and MPTCP turned off. Upgrading the host doesn't change the software inside existing VMs.
boxery ls --refreshshows which ones are outdated, andboxery patch --allpatches those that are running. Patching doesn't change the base itself:boxery build-basedoes that, and it refuses while desktop VMs or snapshots still depend on the old base. Desktops built before 0.9.0 also have no VNC password until they're recreated from a new base. - Controllers on 0.9.0 with a remote host get working ssh once they're updated. Nothing else needs to be done.
v0.9.0
A security-focused release. VMs get no access by default and are isolated from each other. It also adds a new backend, boxery cp, and lets agents ask you for grants. There are breaking changes, so read "Upgrading" first.
Highlights
- LLM access is now a grant. VMs no longer get every LLM provider the host has set up. You give access per provider with
boxery grant VM llm:chatgpt(orllm:openai,llm:anthropic,llm:ollama), and revoking takes effect on the next request (#111). - Agents can ask for grants. With the new
vm_granttool, an agent requestsgithub,ssh-agent,env:VARorfile:access. You approve or decline in a prompt the agent can't answer. Boxery's own secrets,~/.sshand~/.gnupgare always refused (#91, #109). boxery cpcopies files to, from and between VMs, including across hosts. It uses the same code asvm_copy(#87).- Multi-host in pi. pi now has
--vm-host,/vm host, and ahostparameter on every tool, matching MCP (#121). - Several backends on one machine.
boxery host add exe local --backend exeadds one, with its own proxy port and services (#88). - Experimental boat.dev backend.
boxery-host init --backend boatruns VMs as boat.dev sandboxes. It needs a paid boat plan (#80). - Newer toolchain in VMs. VMs get Node 24, and git 2.56 from the git-core PPA instead of Ubuntu's 2.43 (#89).
- Smaller images on libvirt. Space freed in the guest is returned to the host, so snapshots, forks and pool resets stop copying deleted data (#100).
Security
- SSH host keys are pinned for every VM and checked strictly, on every backend (#114).
- Guests are isolated from each other.
- Pool VMs get a new proxy token on each lease, and their grants are tied to that lease. A previous holder can't keep using them after the lease ends (#98).
- The VM desktop requires a VNC password.
boxery desktopsets a fresh one for each session (#110). - MCP over HTTP is locked down.
- The Node download in the image build is checked against its checksum before it's unpacked (#107).
Other changes
- Tool and listing cleanup, based on feedback from agents (#92):
- lookups (
list,shapes,grants,snaps,images,hosts) are only onvm_info; - the VM parameter is called
vmon every tool; - listings use
disk_size/disk_usedandssh_addr.
- lookups (
- Upgrade rollback restores state too. A failed
boxery-host upgradenow restores each profile's lease store and state files along with the code (#102). - Fixed: with several host profiles, each profile's
initor upgrade rewrote the shared guest-to-proxy bridge, so the other profiles' VMs lost the proxy. Each profile now gets its own bridge (#119).
Upgrading
- Upgrade the host before the controllers (
boxery upgrade-host). - Existing VMs lose LLM access until you grant it:
boxery grant VM llm:PROVIDER. - The
legacyhost is gone. Every host needs a registered name. If you still use the old root~/.boxeryprofile, register it withboxery host add NAME --config-dir ~/.boxery.BOXERY_HOSTandBOXERY_HOST_BINare no longer read (#90). - The agentvm migration shims are removed (#83).
- Node >= 22.13 is now required, on both the laptop and the host (#104).
- Prompts or scripts that use the
vm_*tools may need updating for #92 (lookups moved tovm_info,name→vm, renamed listing fields). - libvirt: VMs that were already running stay on the open network until you restart them with
boxery stop NAME && boxery start NAME. - Cloud Hypervisor: run
boxery pin NAME --from-guestonce for each existing VM. - exe.dev: detach the account's default
llmintegration before you create or start VMs.
v0.8.0
A big release: headless VMs, two new experimental backends, background jobs, and much better MCP support.
Highlights
- Headless VMs.
boxery new NAME --headless(orvm_manage new {headless: true}) builds from the stock Ubuntu image without a desktop, and needs nobuild-base. Desktop VMs are still the default (#55). - Background jobs. Use
boxery run --bg,jobs,logs,wait,killandjobs --prune, or thevm_jobstool in MCP and pi. Jobs survive disconnects and report real exit codes (#28, #36). - VM shapes. Pick a named size with
--shape small|standard|large. You can define your own in~/.config/boxery/shapes.jsonon the host (#29). boxery resizechanges a VM's CPUs, memory or disk after it's created (#26).- Host upgrades.
boxery upgrade-hostupdates a host in place. It checks the result and rolls back if the checks fail.boxery versionwarns when the host is behind the controller (#66). - Live desktop in chat. In MCP Apps clients, the
vm_viewtool shows a VM's desktop inline, and you can take control of it (#56).
New backends (experimental)
- exe.dev: run VMs on exe.dev from any machine with ssh, a Mac included (#30).
lsnow reports tunnel state, and the docs explain how to set up an always-on host (#45, #65). - cloud-hypervisor: Linux + KVM without libvirt. Each VM gets its own network isolation (#25).
Agent tools
vm_manageaddsstart,stop,resize,snap-rm,images,new --from, and size parameters (#33).vm_leaselets MCP and pi agents lease VMs from the shared pool. Leases renew while the session is active and are released when it ends (#34).vm_infois a new read-only tool, so clients that support annotations don't ask for approval on lookups (#35).- MCP progress notifications and structured output, sent only to clients that support them (#35).
vm_editis atomic and checks for conflicts. It no longer needs Python in the guest (#44).vm_copystreams transfers with bounded memory and cleans up properly when cancelled (#32).
Reliability
- Host lifecycle operations are serialized, and work left behind by a crash is recovered. New:
boxery-host reconcile(#24). boxery-hosthas been rewritten from bash to Node (#48–#52).- Fixed a hang on Lima hosts when an operation started a VM (#26).
- Screenshots fail with a clear error, instead of returning NaN sizes, when the desktop isn't ready yet (#63).
Upgrading
Stop running boxery-host processes before you upgrade from 0.7.0. The old locks don't coordinate with the new SQLite-based ones (#24).
v0.7.0
The first tagged release of boxery: self-hosted Linux desktop VMs for coding agents. Your agent stays on your laptop and gets vm_* tools that act on VMs on a machine you own.
Highlights
- One-line MCP install.
npx add-mcp boxery-vmadds the boxery MCP server to Claude Code, Codex, Cursor, VS Code and other MCP clients. It works over stdio, or Streamable HTTP for remote use (e.g.tailscale serve). - pi extension.
pi install npm:boxery-vmgives pi explicitvm_bash,vm_read,vm_write,vm_editandvm_copytools, plus computer use and Chrome over CDP. pi's built-in tools still run locally. - Backends. libvirt/KVM on Linux, or Lima on a Mac (
boxery-host init --backend lima+boxery setup local). - Multiple hosts. A single controller and MCP server can manage VMs on several hosts.
- Images, snapshots and forks. All three are built on one image primitive (
VM@LABEL), and it also handles pool resets. - Shared VM pool. Exclusive leases that expire on their own.
- Grants. Give a VM ssh-agent, env or file access per VM, from the controller.
http:grants inject credentials at the edge, so secrets never enter the VM. --jsonoutput for the listing commands.zipis now in the base image.
Breaking changes
- The project was renamed from
agentvmtoboxery, and the npm package isboxery-vm. See Migrating from agentvm. boxery runpasses its arguments to the VM exactly as given, likedocker exec. To run a shell line, useboxery run demo bash -c 'make test'.runalso starts in~/projectnow (#16).
Security
- A security review led to fixes for a host command-injection bug in the controller transport. The LLM proxy also gets an allowlist and limits.
- Grant revocation now tears down ssh-agent sessions.
- Sandboxed ARM64 Chromium now works under Ubuntu's AppArmor.