Give coding agents a disposable VM
AI coding agents belong on a machine you can destroy. Blast radius, clean state per task, snapshots, and the VPS pattern that keeps it cheap.
Why a disposable VM beats your laptop
Give a coding agent a disposable VM and the worst thing it can do is destroy a machine you can rebuild in ten minutes. The agent still gets root, still installs packages, still runs the test suite without asking permission for every step. The difference is where the damage lands. On a laptop, the agent shares a home directory with your SSH keys, your browser profile, your .env files and every other repository you have ever cloned. On a throwaway server, it has a shell, a checkout, and nothing else worth taking.
That is the whole argument, and it is an argument about asymmetry rather than probability. A careful agent on a careful laptop is fine almost every time. The one time it is not, the cost is not a bad commit. It is a restore from backup, if you have one.
Name the blast radius before you argue about it
Blast radius means the set of things a process can reach. For an agent running as your normal user on your normal machine, that set is larger than most people picture.
It includes ~/.ssh/id_ed25519, which is usually unencrypted, because you got tired of typing the passphrase. It includes ~/.aws/credentials and ~/.config/gh/hosts.yml, which are plain text by design. It includes every sibling repository under ~/code, including the ones with production connection strings in a local env file. It includes your shell history, which holds tokens you pasted once. It also includes the network your laptop sits on, which is often a home or office network with unauthenticated services on it.
None of that requires a malicious agent. It requires one confidently wrong command. rm -rf with an unset variable expanding to /, a git clean -xfd in the wrong directory, a docker system prune -af --volumes that takes your local database with it, a helpful chmod -R 777 on a home directory. Agents are trained on the same internet that taught those commands to everyone else.
The mechanism that saves you is not the agent's judgement. It is that the machine holding the damage is one you were willing to lose.
The cost math is boring, which is the point
A small VPS costs a few dollars a month. Recovering a developer laptop costs a day, and that is the good case, where you notice immediately and you had a backup.
Work it out with your own numbers. Take your hourly rate, multiply by the hours it would take to reinstall an operating system, restore a home directory, rotate an SSH key, rotate a personal access token, and re-clone twenty repositories. Compare that to twelve months of the smallest server your provider sells. The break-even sits under one incident per several years, and the incident does not have to be catastrophic to clear the bar. A single afternoon lost to a corrupted local environment already pays for the year.
The second half of the math is snapshots. A snapshot before a risky run turns a bad outcome from "restore my life" into "roll back and try a different prompt". That option does not exist on the laptop you are typing this on, because you cannot snapshot a machine while you are using it as your desk.
The landscape as of July 2026
There are three honest answers to "where should the agent run", and they trade off the same two things: how strong the boundary is, and how much setup you tolerate.
A local micro VM. Tools in this category boot a real virtual machine on your own hardware, mount your repository into it, and let the agent have root inside. clawk is the current example, and its pitch is exactly this post's thesis: give coding agents a disposable Linux VM, not your laptop. As of July 2026 it targets macOS 14 and later on Apple silicon, with experimental Linux support through Firecracker, and it installs with brew install clawkwork/tap/clawk. You run clawk inside a repository to boot the sandbox and attach an agent, clawk down to stop it, and clawk destroy to remove it. The boundary is a hypervisor, which is strong. The limit is that the VM lives on the machine you carry around, so it competes for your memory and it stops when you close the lid.
A container. Docker is the answer most people already have installed, and it is genuinely useful.
docker run --rm -it -v "$PWD:/work" -w /work --network none ubuntu:24.04 bash--rm throws the container away on exit and --network none gives it no network at all, which is a good default for a build or a test run. Be clear about what this does not do: a container shares the host kernel, so a kernel bug is a way out, and the boundary disappears the moment you add --privileged or mount /var/run/docker.sock so the agent can "use Docker". Mounting the Docker socket into a container is equivalent to giving that container root on the host.
A plain VPS you can rebuild. No new tool, a real kernel boundary, provider snapshots, and it keeps running when you shut your laptop. This is the pattern the rest of this guide describes, and it is the one that survives long agent runs, because a job that takes four hours does not care that you went home.
The VPS pattern: give the agent its own user
Start from a hardened box. The first ten minutes on a new VPS cover the parts that are not agent-specific: updates, a non-root login, key-only SSH, a firewall.
Then create an account that exists only for the agent, so a mistake inside it cannot touch anything else on the server.
sudo adduser --disabled-password --gecos "" agent
sudo install -d -m 700 -o agent -g agent /home/agent/work
sudo -u agent -H bash -lc 'id; ls -la ~'--disabled-password means there is no password to guess, and you reach the account with sudo -u agent or an SSH key. Note that agent is deliberately not in the sudo group. An agent with sudo has root, and root can read every other user's files, so the separation you just built is decorative. If the agent genuinely needs to install packages, that is an argument for a whole server it owns, not for handing it sudo on a shared one. The general rules are in least privilege for Linux users on a VPS.
Check the boundary before you trust it. As the agent user, try to read a file belonging to your own account:
sudo -u agent cat /home/you/.ssh/id_ed25519You should see cat: /home/you/.ssh/id_ed25519: Permission denied. If you see key material instead, your home directory is mode 755 and the isolation is not real yet. Fix it with sudo chmod 700 /home/you.
Keep the credentials off the machine entirely
The point of a disposable machine is undone if you copy your production secrets onto it. The rule is simple: nothing on that box should be a credential you would mind rotating this afternoon.
For git, forward your SSH agent instead of copying a key. The private key stays on your laptop and only signature requests cross the connection.
ssh -A agent@203.0.113.10
ssh -T git@github.comThe second command should answer Hi yourname! You've successfully authenticated, but GitHub does not provide shell access. That proves git push will work with no key file present on the server. Run ls -la ~/.ssh on the box afterwards and confirm there is no private key in it.
Agent forwarding has one real caveat, so state it plainly: while you are connected, anyone with root on that server can use the forwarded socket to authenticate as you. On a server whose only other user is you, that is an acceptable trade. On a shared box it is not, and a deploy key scoped to one repository is the better answer. The choices are covered in SSH key management basics.
For API keys, give the agent its own key with its own spending limit, stored in a file the agent user owns at mode 600. When the machine is destroyed, revoke that key rather than wondering whether it leaked. Keeping model spend visible per key is also how the numbers in AI agent cost control on a VPS stay predictable.
Limit what the agent can reach on the network
Filesystem isolation is half the boundary. The other half is egress: what the process is allowed to talk to. Linux can filter outbound traffic by the user that created it, which fits this pattern exactly.
sudo iptables -A OUTPUT -m owner --uid-owner agent -o lo -j ACCEPT
sudo iptables -A OUTPUT -m owner --uid-owner agent -p udp --dport 53 -j ACCEPT
sudo iptables -A OUTPUT -m owner --uid-owner agent -p tcp --dport 443 -j ACCEPT
sudo iptables -A OUTPUT -m owner --uid-owner agent -j REJECTThe rules are read in order, so the final REJECT catches everything the earlier lines did not allow. Test it as the agent:
sudo -u agent curl -sS -m 5 http://example.comThat should fail with curl: (7) Failed to connect to example.com port 80: Connection refused, because the reject rule answers immediately instead of letting the connection hang. An HTTPS request to the same host should still succeed.
Two honest limits. First, these rules are lost at the next reboot unless you save them, with sudo apt install -y iptables-persistent and then sudo netfilter-persistent save. Second, this filters ports and addresses, not names. A rule allowing port 443 allows every HTTPS host on the internet, which is enough to reach the model API and also enough to reach a pastebin. A true domain allow-list needs the traffic to pass through a proxy that reads the requested hostname, which is more machinery than most single-developer setups want. Claim only what you have: port-level egress control, on a machine you were prepared to lose.
Reset to clean state between tasks
Clean state per task is the underrated benefit. An agent that spent three hours on the last ticket left behind installed packages, half-applied migrations, a stale node_modules, and a git working tree with changes nobody reviewed. The next task inherits all of it, and you spend your review budget working out which mess belongs to which run.
The cheap version is a fresh checkout per task.
sudo -u agent -H bash -lc 'rm -rf ~/work/repo && git clone git@github.com:you/repo.git ~/work/repo'The stronger version is a provider snapshot taken once, right after the machine is set up and before any agent has touched it. Restoring that snapshot returns the whole system, packages included, to a known state. Most providers expose this in the control panel or through an API rather than as a command on the box, so the exact steps are your provider's. The discipline is to take the snapshot while the machine is still boring.
Keep anything you care about off the disposable machine, which mostly means pushing branches instead of hoarding them locally. If the box does end up holding something you would miss, back it up properly with restic backups on a VPS. A machine you can destroy is only useful if destroying it is genuinely uneventful.
If you want several isolated environments without paying for several servers, one larger VPS can host guest VMs directly. Nested virtualisation on a VPS covers how that works, including how to check whether your provider allows it.
When a laptop with care is genuinely fine
Be honest about this, because overselling isolation is how people stop listening.
If you are reviewing every command before it runs, a laptop is fine. The permission prompt is a real control, and running Claude Code safely on a server goes through what each level of it actually blocks. If your work is a single repository with no production credentials anywhere on the machine, the blast radius is already small. If your agent sessions are short and supervised, the exposure window is short too.
The answer changes the moment you skip the prompts. Unattended runs, overnight jobs, and any workflow where you approve a plan and walk away all remove the human check that was doing the containment. That is when the machine has to do it instead. The same applies to anything that widens the agent's reach, including running a coding agent on a VPS across several repositories at once.
The decision is not really about how much you trust the model. It is about what is standing next to it when the model is wrong.
FAQ
Is a container enough isolation for a coding agent?
For most work, yes, with two conditions. The container must not run with --privileged, and it must not have /var/run/docker.sock mounted into it, because either one gives the process a path to root on the host. A container shares the host kernel, so the boundary is weaker than a virtual machine. If the agent is running untrusted code pulled from the internet, prefer a real VM or a separate server.
Does the agent need sudo on the server?
No, and giving it sudo undoes the isolation you built, because root can read every other account on the box. Create the agent user without sudo and give it write access only to its own work directory. If the task truly needs package installation, give the agent a whole machine it owns rather than root on a machine it shares.
How do I let the agent push to git without putting my SSH key on the box?
Forward your SSH agent with ssh -A when you connect. Signature requests travel over the connection while the private key stays on your laptop, so ssh -T git@github.com authenticates and git push works with no private key on the server. The caveat is that root on that server can use the forwarded socket while you are connected, so use a repository-scoped deploy key on any machine you share with other people.
What size VPS does an agent need?
Agent work is mostly editing files, running builds, and running tests, so size the machine for the build rather than for the model. A hosted model runs on the provider's hardware, which adds network traffic and almost no local load. Start at 2 GB RAM for scripting work and move to 8 GB if the repository builds containers or compiles anything substantial.
How often should I destroy and rebuild the machine?
Rebuild when the state stops being explainable, and at minimum whenever a credential on the box may have been exposed. A fresh checkout between tasks handles day-to-day drift, and a snapshot taken before the first agent run gives you a clean system image to return to. If rebuilding feels expensive, that is a sign something important is living on a machine you called disposable.