I gave Claude its own machine and got CI for free
2026-07-23
2026-07-23
I delegate a lot of implementation work to Claude. The best change I made to that workflow was to give Claude its own fully provisioned machine, in addition to the setup I run on my laptop. In my case that machine is a Mac mini that runs the exact same environment my project needs. I still run Claude locally. I also run it on the mini, and sometimes on both at the same time. When Claude works on the mini, it runs against its own database, and I control it remotely from whatever device I have with me.
As a side effect, that same machine became my CI runner. But the agent was the point, so I will start there.
Nothing here needs a Mac mini specifically. I happened to have one that was not being used, and I decided to give it a job. Any spare machine works, and so does a VPS. What matters is that the machine is always on and already provisioned, not what it is or where it lives. If you have a cheap Linux machine that stays on, or a rented VPS, that is your setup. Read "Mac mini" everywhere in this post as "the always-on machine I chose."
My project is geospatial. That means the native GIS stack, GDAL, GEOS, PROJ, and related libraries, plus PostGIS running on Postgres just to run the test suite. None of this is installed by default in common Linux distributions. The setup is not large, but it is specific. The dependencies are tied to particular C library versions and behave differently across distributions, so I cannot assume a fresh machine has what the tests need. The real environment is the only environment.
An agent is only as useful as the environment you give it. If Claude cannot run the migrations, cannot reach a real PostGIS database, and cannot run the tests, then it is guessing. For a stack like this, guessing is worthless. So the requirement was simple. Claude needs a real copy of the environment, fully provisioned and always running. Not a mock, and not a reduced container. The same specific setup I run for myself.
The Mac mini is exactly that. It is a second, complete copy of the environment, and its only job is to be the place where Claude works.
The obvious question is why I did not just point an agent at a git worktree on my laptop. I tried that. Worktrees isolate source code and nothing else. Every worktree shares the same Postgres instance and the same migration history. The moment Claude runs a migration on one branch, it has changed the state for everything else on the machine, including whatever I am doing.
A separate machine isolates the part that worktrees cannot: the stateful part. Claude runs many migrations and test runs against the mini's database, and my laptop, on a different branch, never notices. That is real parallel work on branches that change state, which you cannot get by adding more worktrees on one machine.
Because the environment lives on the mini and not on the machine in front of me, it stops mattering where I sit. I connect to the mini and control Claude remotely with Remote Control. I give it a task from my laptop, check its progress from my phone, or review a diff on an iPad from the sofa. The valuable part, the provisioned environment, stays in one place. The client is only a way to view it, and I can use any device.
This is the nice part of the setup. The work does not live on a laptop that sleeps when I close it, or that travels when I travel. It lives on a machine that is always on, always provisioned, and reachable from anywhere on the network.
Once a fully provisioned machine with the whole GIS and PostGIS stack is there and always on, making it a self-hosted CI runner is almost automatic, and it is a good result.
GitHub-hosted runners are a poor fit for a stack with specific, non-default dependencies. Every run starts from an empty machine, so every run pays to install the whole setup again, billed per minute, on every push. On the mini the dependencies are already installed, Postgres and PostGIS are already running, and the cost is fixed, because it is hardware I already owned. I did not set up the mini for CI. CI was simply a result of having the environment there.
I would not be honest if I stopped there.
Self-hosted runner security. Self-hosted runners on a public repository are genuinely dangerous. A malicious pull request can run any code on your machine. This is only safe for me because I run it against a private repository. If yours is public, do not do this without first reading GitHub's warnings about self-hosted runners.
macOS versus Linux in production. I deploy to Linux, so running the agent and CI on macOS is a real difference in environment, and I will not pretend otherwise. What makes me comfortable with it is that the parts most likely to cause me problems are the same on both sides. It is the same GDAL, GEOS, and PROJ libraries, and the same PostGIS, only built for a different operating system. That is where the geospatial correctness I actually worry about lives. The difference between macOS and Linux sits mostly below that layer, in areas my tests do not check. This is a difference I accept on purpose, not one I have removed. In my experience these libraries behaving differently across operating systems is rarely the source of a bug. If something only appears in production, I would check this last, not first.
Single point of failure. It is one machine on my network. If it is down, or if I am on a bad wifi connection, both the delegated workflow and CI stop working.
Because short-lived containers make me pay the setup cost again on every run. You get slow builds from an empty state, fragile layer caching, and image versions that change unexpectedly. The setup is not large, but it is specific and it is stateful, and neither of those fits a container you throw away after each run. The whole strategy is to set this up once and keep it running. That is the opposite of what a fresh container gives you, and the opposite of what an agent working for an hour needs.
If your project is light, ignore all of this. An agent on a worktree is fine, and a spare machine is too much. But if your environment needs specific dependencies that are not installed by default, or a stateful database, the change that helped me most was to give my AI agent its own provisioned machine, not only run it beside me:
One Mac mini, one provisioned environment, and everything else follows from that.