A design system built by a mesh of agents
A consumer genomics platform had shipped an AI-built first pass that validated the product direction and outrun its foundations. There was a component library, a live portal, and a working prototype, with no governed system connecting any of them. I built that layer in roughly seventy hours by running a mesh of AI sessions the way you would run a team: an orchestrator that proposed but never executed, domain owners who each held exactly one surface, a single writer with commit rights, and one human with final say.
- Tracked hours
- 69.8 confirmed, across 26 working days
- Component pages
- 52 in the library
- Components authored
- 16 native, 11 customised, 31 mapped to code
- Color modes
- 4 semantic × 4 device
- Text styles
- 73
- Governance
- RULES v1.0 to v1.6 in five weeks
- Concurrent sessions
- 5 typical, 6 peak
The brief
A fast first pass that had outrun its foundations
Three things were already in place, and understanding all three is what made the brief coherent.
There was an existing component library the team had been building against. There was a live production portal, in use, explicitly not to be touched. And there was an AI-built test portal alongside a generated prototype, heading to a user-interview group — with known gaps the team had already catalogued themselves.
None of that is a failure. A fast AI-built pass had done exactly what it should: proved the direction was right. What it could not do was carry the weight of everything that came next. There was UI, there were designs, there was a library — and nothing governing how they related to each other.
The engagement was the infrastructure layer. A single source of truth, a properly architected token system, a code counterpart that stayed syncable with its upstream, and governance written down well enough to survive my leaving.
The session mesh
Running agents the way you run a team
The interesting part of this project is not that AI wrote most of it. It is the operating structure I had to build before that could work at all.
By the second week a single long-running session could not hold the project. Context ran out, and every restart lost the reasoning behind decisions already made. So I chartered a mesh: several long-running sessions, each owning exactly one surface, coordinating through shared files rather than through conversation.
An architecture session held the operating mechanics and the proposal ledger. It could propose anything and execute nothing.
Three domain sessions — typography, color, components — each owned one slice of the design library and one state file. None of them could touch another's surface, and none could run git.
One session held commit rights. Exactly one. Every repository change in the project went through it.
A builder session, deliberately starved of context, appears later and matters more than its size suggests.
The rule underneath all of it was single-writer surfaces: every artifact had exactly one session permitted to change it, and crossing that line required routing through the orchestrator. That constraint is the entire reason five sessions could write concurrently without destroying each other's work.
Nothing that changed another session's behaviour happened without my recorded approval. Proposals were written as numbered entries with the full dispatch text included, so approving one meant approving exact words rather than a summary of them. Everything was designed to be approvable from a phone.
Identity protocol
The sessions could not tell each other apart
An early failure worth keeping, because the fix generalises.
A session cannot look up its own identifier. Worse, the identifier it would guess — the one visible in its own working path — is not the one other sessions need in order to reach it. I filled the first roster with those guessed values, and messages addressed to them failed silently. Not with an error. They simply went nowhere, which is the worst way for a distributed system to fail.
The fix was a handshake. A new session registers itself as pending and pings any sibling that is already running. The message arrives wearing an envelope containing the sender's real identifier, so the sibling reads it off the envelope and writes it into the roster on the newcomer's behalf. A session cannot know its own name, but anyone it talks to can.
After that, messages routed only by reconciled roster entries, never by a guessed value.
The system
Two axes of theming, on a moving foundation
The token architecture resolves along two independent axes. Color carries four semantic modes; a separate responsive collection carries four device modes. Some scales are deliberately flat across modes so that changing a component's internals has no responsive side effect — a decision that had to be made explicitly and written down, because the alternative silently couples the two axes forever.
The palette was restructured into an intent taxonomy — surface, outline, status, brand — rather than named colors. That rename touched twenty-two variables and re-valued none of them, which meant zero rework downstream.
On the code side, the repository is a fork of an open-source component framework that keeps moving. Early on I fast-forwarded it more than sixteen hundred commits to catch up with upstream, and everything after that had to stay mergeable. Sixteen components the framework had no equivalent for were authored natively; eleven more were customised from what was already there.
Proving it
An experiment, not a demo
A design system is a claim about future work being easier. That claim is testable, so I tested it.
The experiment was to build the same real screen twice, from the repository, by two fresh sessions that knew nothing about how the system was made and could not learn from each other. One built from the raw designs as drawn. The other built from a version rebuilt out of library components first. Every element either mapped to a component, resolved from tokens, partially matched, or had to be hand-rolled — and each builder logged which.
The question behind it was a real one I could not answer by opinion: is it worth asking the client's designers to change how they draw?
The first build is delivered and reported. The rebuilt input for the second passed an independent fidelity check — every sampled node a live instance, the originals provably unmutated, so the comparison stays valid. The second build and the comparison are the last thing outstanding.
What went wrong
Three failures worth keeping
The mesh stalled for five days and nobody misbehaved.
The orchestrator retired having named exactly one blocker: my click on a publish button. I clicked it that evening. Then the whole programme sat still for five days.
Every session had followed its instructions correctly. The retiring orchestrator wrote an accurate handover. The domain session correctly stopped at "blocked on publish." The git session correctly parked its decisions for a successor. Everyone was right and the work stopped anyway — which makes it a defect in the protocol, not in anyone's performance.
Two rules came out of it. A handover has to say how the successor checks whether a gate has opened, not merely that one exists; "someone will click publish" is unverifiable prose, where a two-line API check closes the question on any restart. And when the coordinating role goes quiet, the work parked behind it does not stop accruing — it goes invisible. A stalled domain looks like an idle chat. A stalled coordinator looks exactly like a quiet week.
The session that knew nothing found the biggest problem.
The builder given no context about how the system was built discovered that the components referenced around ninety CSS variables that no shipped stylesheet actually defined. Out of the box, for anyone consuming the system, every component rendered unthemed.
The experiment was designed to test something else entirely. Its deliberately ignorant instrument found the largest architectural gap in the system, and it found it against my own work. That gap defined the next phase.
The official design-to-code binding was unavailable.
Not assumed — proven. Publishing returned a permissions error, and every programmatic route to the same feature turned out to be gated server-side on a plan tier the team was not on. I recorded it as closed rather than leaving it as something to retry hopefully.
The substitute shipped in three layers: a machine-readable manifest mapping every component to its design counterpart, a mandatory reference block in every pull request recording which library version a translation was made from, and back-references from the design side to the code. It cost nothing and it works in both directions.
Outcome
What shipped
A published library of fifty-two component pages with two consumer-visible token collections. A code counterpart with sixteen native components and twenty-five reconciled pages, merged. A machine-readable manifest binding the two. Contribution rules versioned six times in five weeks, and a documented protocol for how the work itself gets run.
Roughly seventy tracked hours across six weeks.
The number is the least interesting part. What it actually demonstrates is that the constraints that make a team work — clear ownership, one writer per surface, decisions recorded with their evidence, handovers that assume the next person knows nothing — are the same constraints that make a mesh of agents work. The substrate changed. The management problem did not.