Agents as a sysadmin
Managing a VPS fleet with Claude Code
Short warning before we start today’s post - maybe don’t try this at home unless your servers are all hobby-grade / not “production”?
AI agents have access to the terminal. That means it has access to most things a human sitting in front of the PC does. One such thing: SSH. Which allows the agent to interact with any SSH target you configured, and easily discover ones if you have Tailscale SSH set up (name@hostname with MagicDNS, actually really easy for me too). And with many headless / VPS setups shipping with root users or passwordless sudo, they can do a lot there.
Claude and other frontier models also know a lot more about Linux than I do, and they can look up live documentation for current facts as well - which might make it safer for me since I sometimes tend… not to keep up to date with the newest news.
Of course, as with all other things about giving LLMs free reign on… anything, it needs caution. I use auto mode (never bypass!), and Claude Opus or other frontier / near-frontier models. I also try to watch over it while it works. And again, don’t try this at home unless you’re really sure. But it did in fact make doing things a lot more easy for me, especially as we continued documenting quirks to local markdown documents.
…The ending to this post is a bit weird, because I’d recommend you try it but then also would suggest you don’t unless you’re very confident in your backups. Anyways, anything you’d like to add?
The markdown document is the part that matters, and it’s worth saying why. A model that knows Linux well will still cheerfully run the destructive thing, because the reason not to isn’t in Linux — it’s in your machine. So the most valuable lines in that file aren’t instructions, they’re prohibitions: never recursively grep this directory, it’s a hundred gigabytes of photos and it will pin the disk for half an hour. Never prune unattached Docker volumes on this host, one of them is the only copy of something. That prune is a perfectly reasonable command everywhere else. Nothing about the model tells it which host it’s on.
The uncomfortable part is that the notes file is also the main way this goes wrong, in two ways worth knowing about before you start.
The first is drift. A notes file describes a machine at the moment someone wrote it down, and machines keep changing afterwards. A script checked into the notes repo had quietly fallen behind the copy actually running on the server — the live one had grown an extra check that the repo copy never got. Editing the tidy version and deploying it would have silently deleted a working monitor, and nothing would have complained. So the rule that ended up in the file is: the host is authoritative, diff against it before editing anything.
The second is that stale facts and current facts look identical in prose. A price, a latency, a cache hit rate — measured once, written down, then read back a month later as though it were still true, in the same confident tone as everything around it. Dating each measurement helps some. Explicitly framing them as evidence for a past decision rather than as current values helps more.
A related one: an agent asked to research a self-hosted service went and read the upstream project, wrote a security assessment from it, and was wrong, because the thing actually running was a fork that had diverged on exactly the point in question. Confidently wrong notes then sat in the file for two weeks being trusted. The fix was boring — vendor the actual source next to the notes and read that instead.
What agents turn out to be unusually good at, though, is a specific failure class: the one where silence looks like health. A backup job had been writing its log to a path the user couldn’t write to; the redirect failed, the job failed, and nothing anywhere said so for six weeks. Nobody was concealing it — it’s just that “no alert” and “no job” produce the same inbox. That class of bug is tedious to hunt by hand and mechanical to hunt with an agent, because finding it is mostly reading a lot of cron tables, log timestamps and service files in one sitting and noticing that a number is older than it should be. The follow-on work was the same shape: put the watchdog on a different machine, because a health report that runs on the host it monitors reports nothing at all when that host dies, which reads as fine.
None of which resolves the ambivalence in this post, and it shouldn’t. Every guardrail described here is a sentence in a markdown file. It is prose, not enforcement — a model that reads it may still act against it, and one that never gets it in context can’t act on it at all. That’s the actual reason for the backups caveat.