The monorepo as more than code
Why the growing pains of coding agents made us redefine our repositories.
A side-effect of giving every developer on our team a coding agent was that PR reviews became an acute bottleneck.
Implementation got faster. Architectural and business-logic decisions did not. As the senior in our small team, I was increasingly the slowest cog in the machine.
What follows is our experience crashing into this new way of writing code, and adapting to it. The crux comes down to one cold fact: an agent’s output is bounded by exactly the context you give it. As we found, the repo becomes the place to hone that context.
Defaulting on our Tech Debt
Our repository structure was an inherited one, built by a team that was optimising for a problem we no longer had - ambiguity. We had a repository for the user-facing frontend, for the backend, for our internal admin panel plus some others. That split was reasonable at the time — it matched how the applications were built, deployed, and staffed; Conway’s law at work. The result was a common story for a small team: tooling versions drifted between repositories, shared packages were not consistently implemented, a couple of SDK upgrades landed in one application but not the others, and a handful of core utility functions had been copied between repos early on and since diverged.
This was always debt we’d have to pay eventually. But with only a few developers and a steady pipeline of business priorities, it was hard to justify.
Coding agents fundamentally changed that. Suddenly, writing code was fast - the fastest in fact. By early 2026, the tech debt collectors came knocking, not through bugs, failures or compliance warnings, but the longest list of PR reviews our team has ever had. We were poorly equipped for agents - keeping three branches and three pull requests in sync, ensuring API contracts were maintained, and that we didn’t regress on logic or UI patterns because previous failures weren’t documented. We could no longer absorb the overhead, so our inkling to reach for a monorepo was no longer a cathartic but unjustifiable clean-up job - it was a solution.
The argument against a monorepo changed
The standard case against monorepos is that what you gain in colocation, shared dependencies and modular packages, you pay for in shared pipelines, heavier tooling and tightly coupled builds.
We felt this almost immediately. Our first attempt was one GitHub Actions workflow per application per environment. With five applications and two shared packages, each across 4 environments, we produced 28 YAML files within the first week. Even trying to abstract common parts into a template, maintaining 28 leaf files itself was painful, and the template began to heave under the weight.
Under the old cost structure, that’s roughly where we would have stayed — a multi-week rewrite you postpone until the pain justifies it. Instead, I threw out the 28 workflows and replaced them with a single internal package, ci-tools, that handles workspace guards, affected-package discovery, deployment safety gates, and orchestration in one place. Emboldened by coding agents, I built it in a day.
Rewriting code got cheap, rewriting documentation got cheaper
The same shift showed up somewhere we didn’t expect: documentation.
Architectural decision records, coding guidelines, review checklists — we had always known these were useful in theory. In practice we trimmed them the way most small teams do, because keeping them accurate cost real developer time, and a stale document is often worse than none — it erodes trust.
Agents moved documentation from something we wrote ourselves, at cost and effort, to something we could regenerate cheaply, on the fly, from evidence that already existed. It also compounded organically: as prompts repeated across the team, each developer ended up with a growing library of prompts, templates and context.
Agents didn’t make us better at writing documentation - like our CI rebuild, they made rewriting and correcting it cheap. But unlike our CI, documentation sprawl was organic, so deriving practices and structure in our docs went from being neglected to non-negotiable.
One repo to rule them all
Once rebuilding infrastructure and rebuilding documentation were both cheap, we started keeping things in the repository we never would have bothered with before: not just ADRs and coding guidelines, but business processes, glossaries and terminology, product decisions, and workflow diagrams — the kind of context that used to live in someone’s head, a Slack thread, or the product owner’s notes.
We keep it now because it changes what an agent, or a new developer, can reason about. A pull request touching billing doesn’t just need the billing code. It benefits from knowing why the current billing model exists, what was tried before it, and which parts of it are considered settled versus provisional. None of that used to be repository content. Most of it is now.
A monorepo used to mean one repository for all code in an application. For us it now means one repository for the system: code, decisions, process, and backlog, together, kept current, because for the first time keeping it current is cheap enough to actually do.
Making it operational
None of this works as an aspiration; it has to be operational or the same tech debt that once haunted us could easily come back amplified.
We our document directory indexes deliberately thin: a filename, a title, and a one-line description per entry, with detail pushed into the document body itself. The index’s only job is routing a human or an agent to the few documents relevant to the current task, without loading the system’s entire history into context on every run. It only works if naming and descriptions stay disciplined — naming, as it’s always been, is still a challenge.
To get the most out of agent context windows, we’ve been intentional about what sits in root-level context (AGENTS.md, CONTEXT.md, README.md) versus what’s injected based on the module an agent is working in (localised README.md, docs/adr, *.plan.md). We’re still evolving this, but prompting agents now feels less like explaining business requirements and more like chatting to our codebase itself.
We use Flue as an agent harness, driven through the same ci-tools package, to run scoped automated reviews on every pull request. Each review gets the diff, the relevant context, and a narrow mandate from a review specification, and checks for exactly the concern it describes. It doesn’t replace architectural review, but it gives us a largely deterministic feedback loop — a floor for code quality regardless of who’s reviewing PRs that day.
Case study: the notification migration
Our notification system was an early implementation that had become a scaling constraint: notifications were stored as an array on an account record, and those arrays were approaching database limits that could eventually have caused outright failures. Notifications also touched almost everything. Most workflow actions send one, and the frontend surfaces them through a dashboard drawer used every session. Fixing the schema meant finding every read and write across the platform, understanding the actual query patterns behind them, standing up new infrastructure, updating application code, and migrating historical data without losing anything.
This is where our recent work began to pay off. The orchestration tooling meant a change touching three applications and two shared packages could be built, tested, and deployed as one coordinated unit instead of five separately timed ones. The documentation meant agents analysing notification usage across the codebase weren’t only pattern-matching on code — they had the business rules for when a notification should fire, and the history of why the array-based schema existed in the first place. We introduced the new table and application code first, then backfilled and cleaned the historical data.
The whole change was built and shipped in two weeks with no downtime. Before the restructure, I couldn’t even put a confident estimate on it — and to keep the backlog moving, I’d been leaning toward an incremental build that would’ve meant running both notification systems side by side for a while.
Consolidation was not free
None of this was free, and it’s worth being specific about where it cost us.
Dependency consolidation was the sharpest cost. Moving every package into one pnpm workspace forced us to reconcile hoisted versus bundled dependencies across the platform, and it surfaced problems in our package hierarchy. Finding them was useful. Being forced to fix them on our migration’s timeline was not.
A monorepo is also inherently more coupled. For a small team with genuinely shared business rules and ownership, that coupling was a win for us even if it meant we had to first trawl through and fix duplicate, stale or incompatible code.
Then there is the increased significance of documentation: what makes it cheap to produce accurately also makes it cheap to produce inconsistently. A primary focus of my PR reviews now is the ADRs and documentation themselves, since they have more influence on future code than existing code does. This has been a learning experience - PRs are always an opportunity for friction, but when reviewing documentation that cannot be tested or run, that opportunity is heightened.
Looking forward
My job has increasingly become context management, but I’d state that more precisely now than I would have a year ago.
It’s more than curating what an agent should build. It’s about deciding, continuously, what belongs in the system’s shared record — because for the first time, adding something to that record and keeping it accurate is both cheap and necessary.