Handing a build to the Mac Mini over SSH and tmux
Contents
Tonight I typed "can u handover the building to the mac mini?" into a Claude Code session on my MacBook, mostly to see what would happen.
Twenty-five minutes later the Mac Mini in the corner of my flat was running its own Claude Code session inside tmux, building the next version of my couples app, and pushing verified commits to main. The MacBook session had set the whole thing up itself.
#Why bother
I've been building Parallax, a couples app, and the next version is a proper multi-sprint build: four database migrations, new screens, feature flags, the lot. That's hours of agent work. I didn't want it tethered to a laptop that goes to sleep when I close the lid.
The Mini is always on. It already runs seven OpenClaw agents and a self-hosted LLM. It's the obvious place for long-running work. The question was whether one Claude session could bootstrap another on a different machine without me touching anything.
#The setup, as the agent did it
The transport already existed. My ~/.ssh/config has a mini host that goes through a Cloudflare Tunnel, so the MacBook can reach the Mini from anywhere without a VPN.
From there the MacBook session did reconnaissance before promising anything, which I appreciated:
- Probed the Mini's toolchain over SSH. First attempt found nothing, because non-interactive SSH gets a bare
PATH. Wrapping everything inzsh -lcfixed it. Node, Docker, the Supabase CLI, and OpenClaw were all there. Claude Code wasn't. - Installed Claude Code globally, cloned the repo (it's public, so plain https), ran
npm install. - Found that the Mini already had Claude credentials from an earlier session, a happy side effect of running Claude Code on both machines. No login dance needed. This was the one step I'd expected to do by hand.
- Started local Supabase for the test suite. This broke: the
vectorlogging container tries to mount a colima Docker socket path that doesn't exist on that machine. The fix issupabase start -x vector,logflare, which skips containers the tests don't need anyway.
Then the actual handover. The MacBook session wrote a kickoff prompt to a file, scp'd it over (after losing a round to nested heredoc quoting), and launched:
tmux new-session -d -s v2build -c ~/dev/parallax
tmux send-keys -t v2build 'claude --dangerously-skip-permissions "$(cat /tmp/v2-kickoff.txt)"' Enter
tmux is the important bit. The session belongs to the Mini, not to my SSH connection. I can close the laptop and the build keeps going. I can also watch it live with ssh mini then tmux attach -t v2build, which is oddly good television.
#Git is the coordination layer
Two agents working the same repo from two machines needs a protocol, and the boring answer turned out to be the right one: git, plus a handover document.
Before handing over, the MacBook session pushed everything it had built (the database foundation: 4 migrations, 506 pgTAP tests passing) and wrote a HANDOVER_S1.md into the repo. What's done, what's next in what order, the rules of the road. One machine builds at a time. Pull before starting. Push small and often.
The Mini session boots, reads the handover doc and the plan, and continues from whatever's on main. The MacBook session checks in every half hour with git log and a tmux pane capture. Foreman, not tether.
First hour of output from the Mini: 4 commits, including the feature-flag infrastructure and the first new screen, each one pushed only after the type checker, 892 jest tests, and a bundle check passed.
#The part that actually mattered
Before any of this, the first build agent on my MacBook reported the database foundation as "ready to ship, all code complete." It had written syntactically valid SQL and called it a day. Docker wasn't running, so it never executed the tests, and said so in small print.
Running them caught five broken test suites, including two regressions in existing tests that its changes had caused. It took another round to get all 36 files green.
That's the whole game with autonomous builds. The agent that writes the code will happily declare victory on vibes. The system around it has to demand evidence: the actual test output, not the claim. The kickoff prompt for the Mini bakes that in, every unit needs the passing output shown before commit.
#On running with permissions off
The Mini session runs with --dangerously-skip-permissions, which is exactly what it sounds like. I thought about this through the lens of the trust budget: the blast radius is one public repo on a machine I own, the work is reversible (it's all git), and the genuinely dangerous things are gated elsewhere. The repo's hooks block secret files from being written, and the features it's building sit behind flags that stay off until I sign off on a safety audit. The agent can build everything and launch nothing.
I wouldn't run this setup against a repo with production credentials in reach. Here, the worst realistic outcome is bad code on main, which is what code review and 506 database tests are for.
#Rough edges
timeout doesn't exist on macOS, which broke one of the probe scripts. Non-interactive SSH quoting is genuinely unpleasant, three levels of nesting before we gave up and used scp. And the supervision loop is still manual-ish: the MacBook session polls on a timer rather than the Mini pushing status anywhere.
Too soon to say if the Mini finishes the whole build order overnight without a nudge. It's four commits in and hasn't stalled yet. If it does stall, the relaunch is one command, and everything pushed stays pushed.