Build the factory, not the app
One machine at home runs a pipeline of AI coding agents that plans, builds, tests, reviews and documents whole projects on its own, and I steer it from my phone. Here is the shape of the machine, what each project actually cost, and the places it still leaks.
TL;DR
- An agent session produces work while you watch it. A factory of agents produces work while you do something else, and the difference between them is architecture.
- Mine finished sixteen projects in six days: each one its own repository with a spec, ticketed commits, tests, a code and a security review, generated technical docs, a small launch site and a cost report.
- The pieces that make it work are unglamorous: one store, a marker per finished phase, every human decision written down as a record something reads back, and a web view with a live event stream.
- Projects cost between 18 and 70 dollars of model spend, most of them between 45 and 55, and the single largest line was design.
- It leaks in specific places: local models that think instead of finishing, parallel work colliding on one file, reviewers that read code without running it, and fix rounds that run out before the problems do.
The unit of work stopped being the project
For most of a year my loop with AI coding agents looked like everyone's. Open a session, describe the thing, watch it build, correct it, and stop when I stopped. Output was tied to attention. A good evening produced a good evening's work.
Then I spent a weekend building the thing that does the loop instead of doing the loop, and in the six days after that it finished sixteen projects. Each one is a repository with a specification that lists its own assumptions, tickets that each landed as one commit, a test suite, browser tests, a code review and a security review with fix rounds, generated technical documentation, a small launch site, and a report naming every model that touched it and what it cost.
Nothing was deployed and nothing was published. The output of the machine is a repository on disk, by design.
The models and prompts were the ones I already had. What changed was the unit of work, which moved up a level from the project to the pipeline that makes projects. Once the thing you build is the pipeline, every improvement compounds across every project that comes after it, so the thing worth asking each morning is what the machine is bad at.
The studio is the registry: every project the factory has finished so far, each with its phases across the row.One process, one store, one window
The whole thing is one long-running process. It holds the pipeline and it serves a small web studio over HTTP with a live event stream, so the page shows phases, tickets and model sessions as they happen.
Everything the process knows lives in one embedded database file. Each finished phase is recorded as a marker, so a restart resumes at the next phase and a crash costs at most one phase.
The studio never does the work. It writes small control rows that the runner reads back: approve this gate, pause before that phase, retry this ticket, change this routing. The indirection felt like ceremony when I wrote it, and it is the reason a phone is enough to run the place.
Ideas enter two ways. A form in the studio, or a Markdown file dropped into a watched folder with a few lines of front matter saying which platforms it targets, whether it may run unattended, and which phases should wait for me.
Each project becomes its own git repository, and each ticket gets its own linked worktree inside it, removed when the ticket lands. That is what lets two tickets build at once without fighting over one checkout, and it keeps one ticket to one commit. Build sessions for local models run in a container per project, which Docker describes as a process with its own file system, its own networking and its own isolated process tree separate from the host. The container sees that one project and read-only copies of the shared skills, and nothing else.
ideas in one long-running process
┌──────────────┐ ┌────────────────────────────────┐
│ studio form │─────────▶│ pipeline: phases, tickets, │
│ watched │ │ retries, escalation, gates │
│ folder (.md) │─────────▶│ │
└──────────────┘ └───────┬───────────────┬────────┘
│ │
phase markers │ │ agent sessions
+ control rows│ │
┌───────▼──────┐ ┌────▼─────────────────┐
│ one store │ │ frontier models: │
│ (embedded db)│ │ on the host, where │
└───────▲──────┘ │ the credentials are │
│ ├──────────────────────┤
┌───────┴──────┐ │ local models: inside │
│ web studio │ │ a per-project │
│ + event feed │ │ container │
└───────▲──────┘ └────┬─────────────────┘
│ │
│ ▼
you, from project repository
any device (one worktree per ticket,
one commit per ticket)The phases, the two gates, and which model does each
A run walks a fixed order, and different work goes to different models because the work is genuinely different. Every session is a coding agent (Claude Code, in the docs' words "an agentic coding tool that reads your codebase, edits files, runs commands, and integrates with your development tools"), started fresh for its one job.
Setup makes the repository and scaffolds it from a template. Plan is the expensive thinking: a frontier model interrogates the idea, writes a specification that states every assumption it had to make, and breaks it into tickets, giving each ticket a model tier and the skill it should work under. Then the plan gate waits for me to approve.
Build runs the tickets, in parallel where their dependencies allow, one fresh session per ticket, one commit per ticket, checks after each. A failing ticket retries twice on its own tier, then escalates to a stronger one, skipping any rung whose model it has already failed on. That ladder is mostly insurance: across the first thirteen runs, exactly one ticket climbed it.
Verify runs the browser tests (Playwright, which its docs call "an end-to-end test framework for modern web apps"), then the full suite, with up to two fix rounds. Reviews are a code review and a security review, each with their own fix rounds, and architecture notes that are listed but never applied, because an architecture change at the end of a run is how you get a broken project at midnight. Then the launch site gets a name, a brand and a page, the technical docs are written, and the run writes a report: models, tickets, costs, escalations, and anything that failed and was accepted anyway. The acceptance gate comes last, and the project is finished only when I accept it. Either gate can be switched off per project, which is how a project runs unattended end to end.
A run in flight: which model is working, what it has spent, and every ticket with the tier and skill it was given.Routing is a dial, and design is where the money goes
Two tables decide who does what. One maps a kind of work (planning, building, design, fixing, reviewing, documenting) to a tier, and the other maps a tier to an actual model. Both are edited in the studio while runs continue, which turned out to matter more than getting them right the first time.
I settled the design model with a bake-off: five models, one launch-page brief, same inputs. The winner was clearly best and clearly not cheapest, the runner-up was close at about a third of the cost, and the best local model was usable only for pages where nobody would care. Having run that once, I stopped arguing with myself about model choice and started re-running the bake-off whenever a new model landed.
The spend surprised me in two ways. First, the numbers are small: projects came in between 18 and 70 dollars of estimated model spend, with most between 45 and 55, against a cap of 100 dollars per project. Second, the largest line is design. The design model accounted for roughly 342 dollars across the runs, more than planning, reviewing and documenting put together, because visual work needs many attempts and each attempt is a long one.
Two brakes keep that honest. There is a cap per project and a cap per day. Past 80 percent of either, build work drops to a cheaper tier; at 100 percent the run pauses instead of failing. And when a model hits its own weekly usage limit, the call waits for the reset, so the project is delayed and never failed. The cost figures come free: run programmatically with JSON output, Claude Code reports a total cost and a per-model breakdown for each session, so the ledger adds up the tool's own estimates.
Every run's estimated spend against its cap. Caps are per project and per day, with a brake at 80 percent.Gates are the remote interface
Besides the two gates there is one escape hatch. When a phase fails, the project moves to a needs-attention state carrying the failure and a named risk, and I pick one of three things: retry it, proceed at my own risk, or cancel.
Proceed is the option I got wrong first. The first version recorded only the name of the risk I had accepted, so proceeding was a quiet way of forgetting. Now an accepted failure is kept whole, in the words I accepted it in, and it keeps appearing in the project's report until it is retried.
That bookkeeping is what makes running it from away possible. The factory lives on a machine at home, and I drive it, including changing its instructions, through a remote-control agent session from my phone. The Remote Control docs describe the property that matters: "When you start a Remote Control session on your machine, Claude keeps running locally the entire time, so your code execution and filesystem access stay on your machine." The session "makes outbound HTTPS requests only and never opens inbound ports on your machine", so there is no tunnel, public URL or open port at home. It is available on the paid plans. It can push a notification to the phone when a long-running task finishes or needs a decision, which suits a pipeline whose interesting moments are rare and unpredictable.
Claude Code also offers a cloud session, one that "runs on cloud infrastructure instead of on your machine". I kept the factory at home because the local models, the containers and every project repository are already there.
On the phone the two windows split the work. The studio shows what the machine is doing and carries the gate and retry buttons, each of which writes a control row. The agent session changes what the machine does next: edit a skill, adjust the routing table, queue the next idea. Reading a long diff and judging a design wait until I am back at a desk, and the gates wait with them. All of that depends on the state living in the store, where any window can reach it.
Routing as data: tiers map to models, kinds of work map to tiers, and both are edited while runs continue.Where the factory leaks
Every one of these cost me a run or a night, and most of them are not model problems.
Local models think instead of finishing. The very first project had one ticket time out three times at an hour each on a local model. Most of its output went on thinking. The transcripts showed it had built the thing test-first, with nineteen tests passing and a clean typecheck at the 48 minute mark, and then spent the rest of its hour hand-fixing indentation it did not like. It never committed. The fixes were dull and effective: put a formatter in the template so whitespace is never the model's problem, tell the builder to commit and stop once the checks pass, inline the essentials of the skills it would otherwise spend eight minutes reading, and size tickets routed to local tiers at about thirty minutes of work, because a ticket the planner sized for a frontier model is too large for a local one. Ollama's default context window is 4096 tokens, which is nowhere near what a coding agent needs, so the context length has to be raised deliberately for every model you route work to.
Killing a session from the outside does not kill it. A timeout that kills the host side of a container exec leaves the session running inside the container, where it carries on competing with its own retry for the same worktree. Time limits have to be enforced inside the container.
A container limits what the agent can reach, and anything placed inside it can be read by whatever runs there. So the container never holds credentials, and the frontier-model sessions, which need them, run on the host. The price is that the strongest models get the least isolation.
Parallel tickets collide on one file. Two tickets that both edit the application shell will both land, and the second one will conflict. Either the planner marks tickets that share a file as dependent, or the scheduler runs them in sequence. Pick one before you turn parallelism up.
A shared dependency folder bites later. The host and the container shared one installed dependency tree, so after a run finished the project would not build on the host until it was reinstalled, because the last install inside the container had left Linux binaries there.
A reviewer that cannot run the code reviews it by reading. The review sessions had no permission to run the test suite or the typecheck, so they reviewed by inspection, which finds different things than execution does. The fix is an allow rule for the test and typecheck commands in the review session's settings, which is the settings docs' own example: a rule set "to let Claude Code run your lint and test commands without asking". Separately, two fix rounds are too few when each round surfaces new problems as well as checking the last round's.
The app and its shop window came out looking like two products. The application was built first with its own palette, then the launch site chose a brand, and nothing carried that brand back into the application. The run was green and the result looked wrong. Any phase that invents a brand has to apply it backwards.
If you build one, build these four things first
You do not need my pipeline to get most of this. Four pieces carry nearly all of it, and they are worth having even in a single-project agent setup:
- One store, and a marker per finished phase. Build resumability in from the first day, because it decides whether you can walk away.
- Every decision as a record. Approvals, pauses, retries and routing changes should be rows something reads back, which turns a terminal-shaped workflow into one you can drive from a train.
- A live view that reads, beside a few controls that write. With the window separate from the machine, the window can be anywhere, and a crashed window leaves the run alone.
- Routing as data. Kinds of work to tiers, tiers to models, edited without a restart. You will change your mind weekly, and re-running a bake-off settles it faster.
This shape suits self-contained greenfield projects where the specification can be written down and the result judged in one sitting. It does not suit a production system with users, where somebody else pays for a wrong change, and it does not replace taste. The factory produced sixteen repositories in six days, and I still looked at every one of them before I accepted it.
Sources
- Overview - Claude Code Docs (opens in a new tab), Claude Code Docs
- Continue local sessions from any device with Remote Control - Claude Code Docs (opens in a new tab), Claude Code Docs
- Claude Code on mobile - Claude Code Docs (opens in a new tab), Claude Code Docs
- Use Claude Code in the cloud - Claude Code Docs (opens in a new tab), Claude Code Docs
- Run Claude Code programmatically - Claude Code Docs (opens in a new tab), Claude Code Docs
- Settings files and precedence - Claude Code Docs (opens in a new tab), Claude Code Docs
- Installation | Playwright (opens in a new tab), playwright.dev
- Git - git-worktree Documentation (opens in a new tab), git-scm.com
- Running containers (opens in a new tab), Docker Inc
- FAQ - Ollama (opens in a new tab), Ollama
ai agentsdeveloper toolinglocal modelsautomationsoftware factory