TL;DR
I’ve argued for poly-repos for most of my career: smaller blast radius, clear ownership, clean compliance scope. Agents changed the math — they win in a monorepo because they can grep across everything in one tree. But repo boundaries were never really about storage; they were a proxy for ownership. For a 50–100 engineer ISV the answer is mono for context, poly for boundaries: give the agent one tree, and move the boundaries from the repo to the path.
Originally published at portfolio.hagzag.com.
One Policy Change, 100 Merge Requests
Over roughly twenty years I’ve worked across hundreds of repositories in more than 150 projects. The pattern that finally broke my poly-repo faith wasn’t an agent. It was CI.
We started with build scripts living inside each repo. Then we did the “right” thing: moved to a shared CI library with a thin YAML config per repo. Cleaner, reusable, governed. And then a policy changed — a new scanning step, a pinned base image, a signing requirement — and the shared-library model showed its real shape: one policy change became a hundred merge requests and two hundred builds.
Poly-repo gave us isolation. It also gave us a hundred places to say the same thing.

Why Agents Prefer One Tree
In Part 1 I argued that source control is following a change in who the developer is. Here’s what that means for layout.
When the repo folder is the agent’s workspace, the agent can see the whole system: the logic, the conventions, the shared libraries, the way the last ten services solved the same problem. I used to think the monorepo’s advantage for agents was history. In practice it’s simpler than that: they win because they can grep across everything in one tree. An agent that can find every caller before changing an interface makes fewer “works on my repo” mistakes than one that sees a single service in isolation.
For a human, a 200-repo estate is navigable because you carry a mental map. An agent starts every session without one. The tree is the map.
The Middle Path That Doesn’t Work
The obvious compromise is to keep the repos and give the agent a shared workspace that aggregates them — a folder of clones, a multi-root workspace, a script that pulls them all.
I’ve tried it. The flaw isn’t performance. It’s that the agent’s context isn’t source-controlled. Which repos, at which revisions, with which AGENTS.md files, assembled by whose script? When the agent produces a bad change, you can’t reproduce what it saw.
Ironically, ClearCase had an answer to this: the config spec — a declarative, shareable description of exactly which versions made up your view. If you go the aggregated-workspace route, version the manifest (Google’s repo tool manifests, git submodules, or a pinned workspace file) and treat it as part of the change. Otherwise, you’ve built an unreproducible developer.
What It Actually Cost Me
Moving toward mono with agents wasn’t free. Two costs showed up fast:
CI minutes. A bigger tree with more frequent agent changes means more pipelines, and most of them repeat work that already ran. The fix isn’t new — it’s the thing ClearCase called winkin: if the inputs are identical, reuse the output. Today that’s content-addressed build and test caching (Bazel remote cache, Nx or Turborepo remote caching) plus affected-only pipelines that build and test only what a change touches. Liz Fong-Jones made the same point to LeadDev: monorepos survive agent volume only if you can detect which dependencies changed. Without that, a monorepo turns the 100-MR problem into a 1-MR-200-builds problem.
Context bloat. One tree means the agent can read everything — and sometimes does. It wanders into unrelated services, burns tokens, and imports conventions from the wrong corner of the codebase. The fix is to make intent local: a short, layered AGENTS.md at the root and in each owned directory, saying what this area is, who owns it, and what not to touch. The succinct version of a change’s intent should live there, versioned with the code, not in a prompt that disappears.

Boundaries Move From the Repo to the Path
My reasons for poly-repo haven’t gone away: blast radius, ownership, and compliance boundaries. What’s changed is where they’re enforced.
- Ownership →
CODEOWNERS(or GitLab code owners) with required approvals per path. - Blast radius → build visibility rules and affected-only deploys, so a change in
payments/can’t silently rebuild and shipauth/. - Access control → path-level permissions. Perforce had
p4 protectdecades ago; Anthropic’s Scion ships directory-level permissions now. Git hosts are weaker here — read access is usually all-or-nothing per repo. - Compliance scope → this is where I still split repos. If a FedRAMP or FIPS boundary means some people (or agents) must not even read certain code, a separate repo is still the honest control.
That’s the verdict: mono for context, poly for boundaries. Default to one tree. Split only where a boundary must be enforced at read time, not just at merge time.
The SOC 2 Question Nobody’s Asking Yet
Anthropic’s post includes two practices worth a pause before you copy them.
First, they dropped the merge queue and test after merge, gating before deploy. SOC 2’s change-management criterion (CC8.1) cares that changes are authorized, tested, and approved before they reach production. If main isn’t production and a deploy gate exists, you’re fine. If you deploy straight from main — as many ISVs do — you’ve just removed your evidence.
Second, review is shifting toward intent rather than every line. When an agent writes the code and a human approves the intent, does that satisfy segregation of duties? I think it can, if the intent is written down (AGENTS.md, a linked spec) and the approval is attributable. But your auditor will ask, so have the answer before they do.
What I’d Do on Monday
For a 50–100 engineer ISV:
- Consolidate application code into one tree; keep compliance-scoped code separate.
- Put boundaries in the path: CODEOWNERS, protected paths, required reviews.
- Make CI affected-only and cached before agent volume makes it expensive.
- Write layered AGENTS.md files — short, owned, versioned.
- If you must aggregate repos, version the manifest.
I spent years telling teams that a repository should be a unit of ownership. I was right about ownership. I was wrong that the repository was the best place to express it.
Discussion