My requirements document for baro was one sentence long: I want to hand it a goal, turn around, and go do something else.
baro is my software factory — a command-line system that takes one goal, plans it into bounded units of work, and runs a collective of concurrent coding agents (planner, architect, workers, critic, gates) until the result is independently reviewed and merged. It is built on Mozaik, and every number in this post comes from its run ledger.
I did not want to supervise an AI coding assistant, and I did not want to review every diff as it streamed by. I wanted to hand the system a goal, walk away, and come back to an open pull request I could trust without re-reading everything the machines did while I was gone.
That sentence turned out to cost months. This post is the anatomy of what it actually took: six mechanisms, each one paid for by a measured failure, each one possible because Mozaik — the TypeScript runtime for concurrent agents — made it cheap to build. And, because honesty is the only marketing I trust: the numbers, including the embarrassing ones.
Early reality check: one of my first serious runs took 118 minutes, cost $6, and merged zero commits. The code was done in minute 35 — the remaining 83 minutes died against a corrupted npm cache. A factory that can write code but cannot survive its own environment is not really a factory; it is just a very expensive way to watch logs.
baro has no orchestrator function calling agents in a loop. There is an event bus, and everything that matters is a participant on it: the planning board, the worker market, every running story (a story is one bounded unit of work), the critic that reviews results, the supervisor that detects stalls, the git coordinator that merges. Nobody calls anybody. Participants publish semantic events and react to the ones they subscribe to.
Mozaik is what makes this a runtime instead of a diagram: agents join an environment, events are delivered to every subscriber, and concurrent participants share state without a fixed workflow. baro adds discipline on top — every event carries authority correlation (which run, which lease, which generation), so a stale or foreign participant cannot smuggle a decision into a live run.
This is also the architecture bet of the whole system: coordination scales when it is an emergent property of participants reacting to shared events, not a script that grows one if-branch per failure mode.
And here is the part I think most multi-agent designs get backwards. Fixed handoffs and point-to-point pipelines are a human pattern — we invented meetings, org charts and interfaces because human attention is scarce, so we ration who talks to whom. Agents do not have that constraint. On a shared bus, watching two hundred peers costs an agent no more than watching one; it can follow whatever it needs, talk to whichever participants matter right now, and coordinate with many of them simultaneously — because these are machines, and parallel attention is their one truly superhuman property. That is why it does not matter whether a run has 2, 20 or 2,000 participants: the ceiling is never anyone's attention, only the runtime's ability to deliver shared events. Wire agents point-to-point and you re-import the human bottleneck into a system that was born without it.
When the plan produces stories, nobody assigns them. The board offers work; workers bid; a broker grants a lease. A worker is a route to a model — and because Mozaik speaks the chat-completions protocol generically, any model with that API can stand behind a route. In a typical baro run, routine stories are executed by a cheap fast model while a stronger model handles planning — and the market can exclude a route mid-run when it starts failing.
The lease is the load-bearing concept here: it carries a generation, so when a story is retried, events from the dead attempt cannot haunt the new one. A market like this is easy to draw on a whiteboard and surprisingly hard to make honest — most of the real work turns out to be careful correlation bookkeeping.
The oldest failure class in the series had one shape: a boundary that judges an agent by a rule nobody told it. The merge gate refused diffs that touched files outside a story's declared surface — correct, and silent. An agent would do something perfectly reasonable in a file it had no way to know belonged to a sibling story, and lose an hour of work at the gate.
The fix became a rule of the whole system: every boundary that judges a story lives in a registry that declares two things from one source — where enforcement lives, and the rule as the judged party needs to hear it. Prompts are projected from that registry. A conformance test refuses any gate that enforces without announcing.
My favorite example: macOS refuses to execute setuid binaries inside any sandbox — including /bin/ps. One agent spent its entire budget brilliantly diagnosing this from first principles, then got failed by the reviewer for running out of turns. Today the sandbox's tool description simply says so, and no agent has paid for that discovery since. That became a rule of the whole system: whatever a boundary enforces, it must also announce.
baro can run coding agents as CLI subprocesses, and it can run them natively — the inference loop inside its own process, on Mozaik's runner. The native lane is where Mozaik stops being a convenience and becomes a capability, because owning the loop enables things a subprocess structurally cannot do:
Live rules. When the plan changes mid-run and file ownership shifts, the running agent's write tools re-target immediately — the enforcement object is read at every tool call, and the revised rule is injected at the next inference round.
Provable quiescence. When a story suspends to wait on a dependency, the host must know nothing is still writing before it snapshots the worktree. With a subprocess, all you really have is the process table and some hope. In-process, an empty set of in-flight tool invocations is a proof, not an inference.
Peer awareness without waste. When a sibling story discovers a trap, the note reaches a running agent at its next round boundary — informing the very next model call — without consuming a review turn or reopening a finished story.
The single biggest measured number in the whole project: at one point, 45% of a story's wall-clock time was spent after its last file write — proving, re-running, formatting evidence. In one recent run an agent wrote its code in twenty minutes and then spent over an hour re-running full test suites under concurrent-story load. That number changed how I think about this whole class of systems: the dominant cost of a software factory is not writing the code — it is proving the code.
baro's answer is a chain of independent institutions. The critic judges against captured command output bound to the exact bytes changed — edit anything after your evidence and the evidence is void. The merge gate refuses out-of-surface diffs. And a run-level verifier builds and tests the fully-merged tree once, after integration — so each story now owes only its own perimeter: the tests it declared, plus targeted coverage of the files it touched. The worker reports on its own work, but only the system certifies it — and that difference is the reason I can walk away at all.
No plan survives contact with a real repository. baro's plan is a versioned dependency graph that changes while it executes: a running story can propose new work through a closed-schema tool, the board validates and persists the mutation, and every decision is replayable by id. Failed stories get recovery lanes with fresh worktrees; goal invariants that lose coverage spawn remediation stories automatically.
The point is not that planning is smart. The point is that planning is on the bus — the same event-and-authority machinery that runs stories also runs changes to the plan itself.
Here is what all of this looks like when it runs — one real run, this morning, on baro's own repository. The goal: introduce a shared configuration parser in both stacks (TypeScript and Rust) and migrate three call sites onto it, each with tests proving both paths.
The planning brain took its time, on purpose. Intake bounded the goal; the architect then spent ~16 minutes reading the repository and naming file-level evidence for every architecture obligation before a single line was planned. Then the progressive planner published the plan as an immutable fragment — two stories, one per stack, each declaring exactly which files it would write and which obligations it owns.
And then the hands took over. The market leased both stories to a fast, cheap model within ten seconds of each other. Running concurrently, the TypeScript story went from first tool call to reviewed-and-merged in 3 minutes 49 seconds; the Rust story in 5 minutes 44 seconds — each running only its own perimeter tests, because the run-level gate owns the whole-tree proof. The moment the last story merged, that gate started: build, both suites, typecheck, on the fully-merged branch, once.
One run, minute by minute
slow deliberate planning, fast concurrent execution, one independent proof
The gate finished in seven minutes: builds green, typecheck green, the whole Rust suite green — and then it marked the run as failed. The work itself was actually done and correct. What went red was a single known flaky timing test in a part of the codebase the stories never even touched; it passes cleanly in isolation. In other words, a small bug in baro's gate — it does not yet apply the same rule the stories already follow, where a load failure is retried once in isolation and the isolated result decides — mislabeled a finished run. We are already fixing it. I am telling you this instead of hiding it because it shows the gate erring in the right direction: it would rather fail a finished run than wave through a red suite.
Two more things worth being honest about. This was a single run on a freshly-fixed harness, not an average — the same goal had died twice in the preceding days, each death buying one of the fixes described above. And while it ran, I drank a coffee and smoked a couple of cigarettes. The factory did not need me, and that fact matters more than any single number in this post.
One more thing this shape buys you: it scales with the size of the task. The run above is deliberately small — a goal that condensed into two stories and finished within the hour. On a bigger goal, the same machinery has planned a graph of over thirty stories and shipped 808 passing NestJS tests in a single run — using the same bus, the same market and the same gates, only with more participants. That is the practical payoff of the attention argument from earlier: the architecture simply does not care whether it is coordinating two stories or thirty.
The parts of baro that still feel like scaffolding are exactly the parts the upcoming Mozaik version removes. Today's runtime streams tokens without usage accounting or message assembly, so baro's native lane runs non-streaming with a conservative backstop — that scaffolding gets deleted when streaming carries usage end-to-end. And the planner and architect, which today talk to the bus through a host-side adapter, become full bus participants like everything else: one contract, one runtime, no translation layer.
I am deliberately not promising dates. I am promising direction: every version of Mozaik so far has let baro delete code I was not proud of.
One experiment ran through this whole period: the same goal — a shared configuration parser plus three migrations, in baro's own repository — executed again and again on an evolving harness. After every round we did an autopsy of where the time actually died, fixed that one boundary, and ran the same goal again. The chart below tracks a single number across four of those rounds: how long the fastest story took from starting work to having its branch reviewed and merged.
Read it carefully, because the models did not change between these rounds — the boundaries did. Round 1's 24.7 minutes were not spent writing code: they died against a shell timeout smaller than the test suite, evidence re-runs the agent did not know were redundant, and rules it learned only by breaking them. Each fix removed one of those walls, and the same work collapsed to under three minutes. That is the entire thesis of this post in one picture: the cost of an agent factory lives at its boundaries, not in its model.
And this improvement loop is itself a Mozaik dividend. Because every verdict, tool call and gate is an event on a shared bus, every failure leaves a trace you can actually read — the autopsies wrote themselves. And because every mechanism is one participant, each fix stayed local: one round's post-mortem changed one participant, nothing else, and the next round measured the difference. A factory you cannot observe is a factory you cannot improve.
Fastest story, goal → merged branch
minutes; same goal, four harness iterations, July–August 2026
| Fastest story, goal → merged branch | 2 min 33 s |
| Story completion, July → August | ~25 min → under 4 min |
| Stories executing concurrently in one run | 4 |
| Story time spent proving (before the perimeter contract) | ~45% |
| Most expensive lesson | 118 min, $6, 0 commits — a corrupted npm cache |
| Boundaries converted into self-announcing gates | 4 |
What baro is genuinely good at: several independent changes at once across disjoint files — that is where coordinated parallelism pays; goals with measurable acceptance; pattern migrations across a codebase; work that gets discovered while executing. Story completion went from ~25 minutes in July to under 4 minutes in August, with the fastest merges around two and a half — each round of failures lowered the next bottleneck.
What it is still bad at, plainly: small tasks, where the contract machinery costs more than the work; verification under load, where concurrent test suites produce timing flakes that read as failures; and upstream provider hiccups, which recovery absorbs but never for free. I wanted a factory I could leave for an evening. What I have is a factory I can leave for a stretch — and that tells me, precisely and in writing, why not longer. Every run buys back a few more minutes.
Here is the part I want you to take seriously: nothing above required a research lab. Every mechanism in baro is participants reacting to events — and that is buildable at hackathon scale.
Two agents and a judge sharing a bus is a weekend project. A tiny work market where models bid for tasks is another weekend. A gate that announces its own rule is an afternoon. You will not build a whole factory in two days, but you can absolutely build the one machine that makes you want to build the rest of it.
And there is no better excuse than this: we are running an online hackathon on Mozaik. Kickoff livestream on September 4, build weekend September 5–6, winners on September 13. Concurrent agents, shared state, no fixed handoffs — starter templates provided, no prior Mozaik experience needed, solo or with a team.
Build a concurrent multi-agent system with Mozaik, September 5–6 — and walk away while it runs. That feeling is the whole point of this hackathon.
Register for the Mozaik hackathon →
Join our Discord → — find teammates, get help, show us what you are building.
With tools and technology we already have, we can build much more valuable systems than most projects today. We can write software that is a pleasure to use and a pleasure to work on; software that doesn't box us in as it grows, but creates new opportunities and continues to add value for its owners.
Newsletter
For developers who want to learn how to build self-organizing agents.
Join our online hackathon
Join our online hackathon for building multi-agent systems.