Most teams running coding agents at any scale have converged on the same machine without agreeing on a name for it. Work arrives from somewhere. Something decides an agent should pick it up. The agent runs on a computer that has the right toolchain, produces a branch, and something else decides whether a human ever sees it.
That machine is a software factory, and on episode 71 of AI That Works, Dex Horthy of HumanLayer and Vaibhav Gupta of Boundary spent an hour taking one apart on screen — including the one Boundary actually runs to maintain the BAML language. What follows is that architecture, the layers it decomposes into, and the structural problem underneath the whole category.
We have written about the harness before: the eleven primitives that sit between a model and useful work. The harness is one layer of this. This post is about what surrounds it.
The bottleneck moved
The original factory has a human building the thing and a human reviewing it. You swap the first human for an agent, then get the agent to test its own work, and the build step gets fast. Review does not. It is still one person reading a diff at the speed a person reads.
Every design decision below follows from that. The interesting question stopped being how do I get an agent to write this and became how do I spend the least human attention per merged change — which is an architecture problem, not a prompting one.
The four layers
Bottom of the stack
- 01Computewhere a session physically runs
- 02Dev environmentruntimes, services, identity, previews
Top of the stack
- 03Harnessthe agent loop, inner and outer
- 04Control planedispatch, traces, gates, spend, memory
Every one of the four has a mature buy option and a viable build option. The value of naming them is that it converts one impossible question — should we buy an agent platform? — into four answerable ones.
Compute
The lowest layer is the least interesting, which is a compliment. You need somewhere for agent sessions to execute, and the options run from your own EC2 or Kubernetes, through bring-your-own-cloud vendors that hand you a sandbox API while the machines stay in your account, to fully hosted execution where you send a request and never see infrastructure.
Boundary's answer is a rack of MacBooks and Mac minis in the office. Two reasons, both unglamorous: the toolchain is already installed so there is no boot time, and they had spare hardware lying around. No containers, no gVisor, no sandbox.
That last part sounds reckless until you follow the trust argument, which is the actually transferable idea here. Boundary never executes anything derived from an untrusted source. Raw user feedback is treated as untrustworthy input, but it is never run — it is read by a prompt that produces a reproduction case, and the reproduction is theirs. By the time code executes, it was generated inside their own system. Isolation buys you nothing you did not already have.
Worth being honest about the shape of that argument, because it is easy to misapply: sandboxing is a function of what enters the execution boundary, not of how important the code is. If arbitrary text from your users ever reaches a shell, you need the sandbox regardless of how trusted the rest of the pipeline is.
The dev environment
This is the contested layer, and the one most likely to be underestimated.
The dev environment is everything an agent needs before it can do work that means anything: language runtimes at the right versions, the ability to reach internal services, a database pointed at the right place, credentials scoped to an identity, and — for anything with a UI — a preview URL a human can open.
Horthy's position is that you will want to own this, and the argument is a friction argument rather than a security one. Telling a sandbox vendor to use a base image with a specific Rust version is easy. Poking holes from a vendor's cloud into the shared internal services your stack needs, when you have a hundred repos and cannot run them all in the box, is not. Neither is debugging a toolchain that misbehaves because the sandbox runs a partial kernel that is missing a syscall you depend on.
If you are building small self-contained apps, none of this bites and a fully hosted stack is genuinely fine. The friction scales with how much of your company an agent has to reach to do its job.
There is also a prior art argument that is hard to unhear once you have heard it. Anyone who worked at Google or Meta has already used this layer in its finished form: you get a good laptop and never write code on it, because you get a remote workstation instead. Provisioned on demand, identity attached, internal services reachable by default, and every web service you start gets a per-user subdomain you can send to a PM — internal-only unless you explicitly escalate it. The industry is currently rebuilding that, one startup at a time.
Which raises the question of whether your environments are pets or cattle — a distinction that is thirty years old and newly load-bearing. A pet is a machine you set up by hand and repair when it breaks. Cattle are provisioned by a script and replaced rather than fixed. Boundary's MacBooks are pets: adding one means someone pulls it off a shelf, clones a repo and runs a provisioning script. That is a fine place to be, and Horthy is explicit that it is a fine place to start, but it is worth knowing which one you have chosen. The tell is simple — is there a button that makes a new machine ready to accept work, or is there a person?
One related decision that catches teams out: if your code lives in eighty repos, the factory gets much harder. The recommended workaround is to simulate a monorepo — a coordination repo one level up whose only job is to hold the instructions file that tells the agent where everything else is. Not submodules, which pin commits and make you commit in two places for every change. The model does not need a git relationship between the repos. It needs to be told where they are.
The harness
The harness splits cleanly in two, and the split is the useful part.
The inner harness is the agent loop itself — Claude Code, Codex, Amp, Devin, Factory, opencode, or something you build. The outer harness is everything you wrap around it: skills, MCP servers, hooks, compaction policy, and the deterministic loops that drive a task to completion.
These trade off against each other. Buy a thick inner harness that arrives with a browser, testing and a toolchain, and your outer harness can be thin. Choose a minimal inner harness and you will write more outer harness yourself, in exchange for controlling all of it.
Boundary runs Claude Code and Codex in headless mode, streaming JSON to a transcript file the
factory tails — deliberately swappable, because it is a CLI and CLIs can be exchanged. The
interesting work is in the outer layer, and it is less exotic than the phrase suggests. It is
while loops:
- Fix until the reviewer is satisfied. Their PR bot reviews; the agent addresses the comments; repeat. No human is notified until the bot is happy — or until three iterations have passed, at which point a human is.
- Drive to merge. Once a human has approved, an agent keeps the branch rebased on main and shepherds it through the merge queue. An agentic merge queue, essentially, built because CI is slow and conflicts happen while it runs.
Neither loop is clever. Both convert a category of interruption into something that happens without anyone watching, which is the entire point. Note also what is not automated: a human still presses merge.
The control plane
The top layer is the one Horthy calls the most underserved, and it is where the actual product category is forming. Its job list:
- Dispatch new work, from a webhook, a schedule, a Slack message or a person
- Show session traces, plans and architecture documents while they are being produced
- Provide review and iteration on the work, PR-shaped but not necessarily inside GitHub
- Handle permissions, audit, and who can reach which services
- Manage spend and budget
- Carry compounding engineering — the memory system that turns "every engineer corrects the agent the same way all day" into something the outer harness knows next time
Boundary's implementation is two pieces. Each machine in the pool runs a local web server exposing a REST API, made reachable through a tunnel. A hosted web app sits above them holding the database, listening to Linear, Slack and GitHub webhooks, and dispatching to the pool.
Control plane — hosted
- 01Webhook listenerLinear, Slack, GitHub
- 02Dispatcher + databasestate, queue, its own API
Machine pool — owned hardware
- 03Local REST serverone per machine, tunnelled
- 04Pre-installed toolchainno boot time by design
- 05Headless CLI sessionstreams JSON to a transcript
- 06Outer-harness loopsfix-until-green, drive-to-merge
The pipeline that produces the work
The architecture above is the how. The more instructive part of the episode was the what — the pipeline Boundary built to turn user feedback into merged fixes, and the assumption it is designed around: no feedback can be trusted, including your own agents' feedback.
- 01Feedback arrivesFrom a user, or from an agent that hit something. Treated as an unverified claim, not as a task.
- 02Check it against the latest buildMost reports are against a version that has moved on.Already fixed → notify the reporter, stop here
- 03Deduplicate against known reproductionsNobody has a good deduplication agent. If it catches half, it has paid for itself.Duplicate → attach to the existing case
- 04Spend tokens building a reproductionThe system generates candidate reproductions until one holds. This is where the engineering effort goes, because everything downstream depends on it.No reproduction possible → hand to a human
- 05Now create the issueIssues are created after a reproduction exists, not from the feedback. The issue's payload is the reproduction.
- 06Run every reproduction on every PRCheap — CPU time, no browsers for most of it. Every open issue is continuously re-checked for having been fixed by something else.
- 07Classify the difficultyAn agent judgement, self-correcting: if a fix classified as small lands at 500 lines, it is reclassified.
- 08Assign a shepherdA named human gets a Slack message: here is the repro, here is the fix, read the PR. Or: this one is hard, here is a plan — approve it or take it into your own agent.
Four things about this design are worth stealing regardless of what you are building.
The reproduction is the artifact, not the report. A bug report is a claim about the world. A reproduction is a test. Restructuring the pipeline so an issue cannot exist without one moves the entire system from arguing about descriptions to running code — and it makes step 6, which is otherwise impossible, trivial.
Every change to the pipeline must report its own metrics. Boundary's one hard rule is that a PR touching the pipeline has to push reproduction results, so the accuracy of each subsystem version is visible. Their deduplication step is measurably worse than they expected, which they know because the rule forced the measurement. This is verification applied to your own tooling rather than only to the product.
Aim for 95%, not 100%. Gupta's framing: a fully automatic system is much harder than a 95% automatic one, and the last five percent is where all the pathological cases live. Design the escape hatches as first-class paths — three of the eight steps above are exits — and the system stays buildable.
Push human time down, not out. Every step exists to reduce what a person has to hold in their head, not to remove the person. The shepherd still reads the PR. They just read it with a reproduction, a diagnosis and a diff in front of them.
The structural problem: buying a layer buys everything under it
Here is where the category is stuck, and it is the most useful thing in the episode.
The four layers are conceptually independent. In practice, buying at any layer forces you to buy everything beneath it. Want orchestration so you can dispatch agents from Slack? Today you either build the whole vertical stack or you buy the whole vertical stack — including the compute and dev environment you may have very good reasons to own.
Horthy's phrase for the fix is composition over inheritance, and the missing pieces are interfaces rather than products:
- ACP (Agent Client Protocol) connects an editor to an agent. Real, adopted, and deliberately narrow — it was designed for the editor case, not for a control plane driving a fleet.
- AG-UI broadcasts an agent's events to a UI. Also real, also narrower than the problem.
- Neither carries hooks — the lifecycle events a control plane needs to intervene on. And hooks are exactly where standardisation is hardest, because every harness has made a different bet. Claude Code, Codex and pi expose different lifecycle events; opencode models extension as a plugin system entirely. These are legitimate design differences, not an oversight, which is why a lowest-common-denominator abstraction over them is worse than useless.
Gupta's analogy is the one that will stay with me. Web UI was a mess of competing abstractions until React proposed that state is the primitive and everything else falls out of it. Nobody has found the equivalent primitive for coding harnesses yet. And you could not have designed React the first year the web existed — you had to watch a lot of things go wrong first.
That is also the honest answer to "why is there no open-source control plane?" Partly because everyone building one is building a product. But mostly because a control plane encodes a company's working definitions — what counts as an issue, when a human gets pinged, what a review gate means — and those differ enough that there is little to share. Boundary evaluated using an off-the-shelf orchestration layer and declined, not because it was bad, but because their pipeline needs its own definition of an issue before a normal issue tracker becomes relevant. MCP is the counterexample worth studying: it standardised one narrow interface and unlocked an ecosystem without anyone agreeing on products.
Where this leaves you
The stack is a decision framework, so use it as one.
| Layer | Default | Why |
|---|---|---|
| Compute | Rent | Well-understood, competitive, low switching cost. Own it only if you already have hardware or a hard residency requirement. |
| Dev environment | Own | Highest friction inside somebody else's cloud, and the friction grows with the size of your internal surface area. |
| Harness | Rent, stay swappable | It is a CLI. Treat inner harnesses as interchangeable and keep the value in the outer harness you wrote. |
| Control plane | Build the thin part | Buy dispatch and traces if a vendor's model fits. Your definitions of issue, ready and escalate are yours, and they are the part that matters. |
And one test that cuts through all of it: for each layer, what happens if you have to replace it next quarter? The layers where the honest answer is "we would rewrite everything" are the ones where you have accepted a dependency you did not consciously choose. That is not necessarily wrong. It should just be a decision rather than a discovery.
The factory is a real architecture with real seams. Most teams are building one whether or not they have drawn it. Drawing it is cheap, and it is the only way to notice which parts you have already bought.
Common questions
- What is a software factory for AI coding agents?
- The system that takes work from a request to a merged pull request with agents doing the building and testing. It decomposes into four layers — compute, dev environment, harness and control plane — and each one can be bought or built independently, at least in principle.
- Which layer of the stack should you own?
- The dev environment, in most cases. It is where your language runtimes, internal service access, preview URLs and identity provisioning live, and it is the layer that generates the most friction when it runs inside somebody else's cloud. Compute is the easiest to rent.
- What is the difference between the inner and outer harness?
- The inner harness is the agent loop itself — Claude Code, Codex, opencode. The outer harness is everything you wrap around it: skills, MCP servers, hooks, and the deterministic loops that drive a task to completion. Buy a thick inner harness and your outer one stays thin, and the reverse.
- Why is there no open-source control plane?
- Because the control plane encodes a company's working definitions — what counts as an issue, when a human is pinged, what a review gate is — and those differ enough between teams that a shared implementation has little surface to standardise. The interfaces are the tractable part, not the product.
- AI
- Agents
- Architecture
