Jarvis · chapter 4 of 4

Laying out code so parallel agents don't collide

With about ten agents editing at once, shared files jammed before the CPUs did, so v2 gives every piece of code its own file with its test beside it.

In Jarvis v1’s last week, the merge conflicts clustered in four files. The iPhone app’s shared model conflicted in 20 PRs, a snapshot fixture in 18, the API schema module in 17, and an enums file in 17. The schema module was 9,245 lines and doubled as the domain model. One person editing a big shared file is an inconvenience. About ten agents editing it at once is a queue.

median source file lines 236 v1, Oct 9 70 v2, Oct 28 files over 500 lines files 765 v1, Oct 9 96 v2, Oct 28 tests beside their code share of test files 0.1% v1, Oct 9 67.4% v2, Oct 28 2026, main's last commit of the day; each panel on its own scale from zero
Fig. 01 — The same codebase, before and after it was laid out for agents. On October 9, v1's median source file was 236 lines, 765 of its 3,560 files ran past 500 lines, and 0.1% of its tests sat beside the code they tested. On October 28, v2's median was 70 lines, 96 of 4,019 files ran past 500, and 67.4% of tests sat beside their code.

Fig. 01 · pinch or scroll to zoom · drag to pan

What I believed

For most of v1 the limit I chased was compute. Swift builds and 600 simulator processes pushed the laptop to a load of 437 on 18 cores, and the first Mac Studio arrived on October 7. I kept believing it into late October: “We were having lots of issues with not having enough CPU capacity to be able to run all of our deterministic tests and to be able to run the unit test and gates and everything else.”

Meanwhile v1 kept its tests in their own trees, had no fakes or stories, and let a file grow whenever a change needed one more thing in it. By October 9 its median source file was 236 lines and 765 files ran past 500.

What broke

v2 started on a fresh layout on October 10 and hit the same wall within a day. The PRs that fixed it say why: “Merge conflicts ate 17-28% of gate runs on 2026-10-11 … because every lane hand-edited the same shared files.” The app’s test file, the shell, the title bar, and the hand-written registries were all shared lists that every new screen had to touch.

Two days later a 168-PR refactor moved the web app’s screens into domains. One generated contract file showed up in 98 conflict runs while the build host sat at about 0.06 load per core. The machines were idle. All 42 open PRs were frozen until the refactor landed. The fleet’s own record put it in one line: “the throughput limit was shared files, not hosts.”

What I do now

The layout is written down, and the gate enforces it. From the layout doc: “One unit per file … The unit’s story, test and fixture sit beside it.” And: “New things register by discovery: you add a file in the right place … You never add a line to a shared list.” A layout manifest declares 143 file kinds, and every file in the repository has to match exactly one. Agents find things by asking, not by searching: “Ask make layout-lookup; it answers by exact match only, never by grep.”

Each port ships a fake beside it, and screens and components carry Storybook stories. On October 29 main holds 596 stories and 179 fakes. Hot files get one open writer at a time, and conflicts on baseline lists are resolved by a script instead of an agent.

The shape moved a long way. The median source file went from 236 lines to 70, the p90 from 805 to 255, and the largest file from 10,762 lines to 2,132. Tests sitting beside the code they test went from 0.1% to 67.4%, and 93.1% in the web app. The overall share has been falling as the Python daemon grows with its tests in separate directories.

What it did to conflicts

Here’s where the easy number is wrong. Conflicted syncs per day fell 71.6%, from v1’s last week to v2’s. Merges per day fell 63.2% over the same span. Per merge, the drop is 23%: from 33.1 conflicted syncs per 100 merges to 25.5. The share of merged PRs that needed a conflict resolved didn’t move at all, 20.8% to 20.4%.

So I don’t claim 70% fewer conflicts. The layout’s real effect is on where conflicts happen. The worst file in a week went from 20 conflicted PRs to 8, and the hot spots moved from shared models and fixtures to docs, skills, and probe tests. Other changes landed in the same days and can’t be separated from the layout: conflict-aware dispatch with one owner per hot file, a work-in-progress limit, the scripted resolver, and a lower merge rate.

What’s still open

The files are creeping back up. The median was 59 lines on October 15 and 70 on October 28, and the p90 went from 203 to 255.

The shared file also found a new home. On October 28 the hottest files in the repository were the ratchet lists, the files that let old code skip a new rule, and the gate chapter has that jam. Layout can’t fix what the scheduler sends at once. Cards have to say what they’ll touch, “so that when we want to schedule the cards that we can kind of schedule them properly so that we’re not doing overlapping competing concerns that eventually slow down the entire fleet when they conflict in the PR stage.” Card linting for that, and lanes that cap each area, are designed and filed, not built.

A layout for agents is a scheduling decision made in advance. Every file that only one card needs is a conflict that can’t happen.

How this was counted

Source files are code files on main at the last commit of the day, generated and vendored paths and gate fixture trees excluded. A test counts as beside its code when it sits in a directory that also holds non-test source. Conflicts come from replaying every merge of main into a PR branch with git merge-tree and counting the ones Git can’t merge cleanly, for every PR merged from September 14 to October 28. The quotes are mine from an interview on October 29, 2026, except where the text credits a document or the fleet’s records.

This project

This project, in order

Start

Tell me what’s stuck

I’ll tell you in about a day whether I’m the right person. The first conversation is fit, not a free architecture review.