A Planner That Will Not Onboard Anything
The tool that decides how to onboard a new service into my homelab has no ability to onboard a service. That separation is the design, not a limitation.
Bringing a new service into my homelab is repetitive: classify what it is, decide where it lives, work out whether it needs a database, a backup target, a monitor, a route, a DNS record, and which of those are actually load-bearing. It is exactly the shape of work that invites automation, and exactly the shape of work where automation goes wrong quietly.
So it is split in two, and the split is at the verb.
Level 4A classifies and plans. It cannot act.
The planner reads candidate records, classifies them, and writes a local operator plan — JSON and Markdown, in a runtime directory. That is the whole capability. It does not create containers, write compose files, register DNS, or touch a host. Even its own writing is opt-in behind an apply flag; without it, the tool prints what it would have written.
The executor is a separate level, separately gated, requiring a durable approval record that names the exact plan it is allowed to act on. Live execution is disabled by default.
Enabling a candidate is a rename
Candidate records live as files in a directory. Files ending in the normal data extensions are scanned; files ending in .disabled are not.
This means the act of promoting an example into a live candidate is a file rename, which shows up in a diff as a rename, in a pull request as a reviewable change, and in the repository history as a dated event with an author.
I like this far more than a boolean field inside the file. An enabled flag flipped from false to true is one character in a diff, easy to miss in review and impossible to see in a directory listing. A rename is visible from outside the file. When you are building something whose safety depends on humans noticing, the switch should be somewhere a human is already looking.
Why planner-only is not a half-measure
I keep meeting the assumption that a system which plans but does not act is unfinished — a step on the way to autonomy. In my homelab it is the opposite. The bottleneck was never my ability to run commands. It was knowing which commands were worth running.
A tool that hands me a correct, cited, complete plan has removed the part I am bad at. Executing it takes minutes and I am good at that. Automating the half I am good at, to save the half I am not, would be the wrong trade — and it would spend the entire safety budget of the system on the least valuable step.
Written by
Adrian Romo
Senior Backend Engineer building scalable Python APIs, AWS Lambda architectures, voice systems, and enterprise integrations.
Related
Keep reading
Assembled Primitives vs. a Platform
I built a voice agent out of cloud primitives, and it worked. It has since been replaced by a purpose-built voice platform, and I think that was the right call.
Six Posts a Day, and the Scheduler That Learned to Say When
A social pipeline that published one Reel a day and nothing else, because per-format quotas were ceilings and nothing was asking for the other formats.
Seconds of Work, Hours of Residency
My morning briefing started failing. Ollama was up and returned HTTP 500, because a 21-second image render was still holding 6.6 GB of VRAM hours later.
Keep going
Where to next?
Browse more technical writing, see the engineering case studies, or reach out directly.