Most demos of AI coding agents happen in a single repository, where the whole world the agent needs to understand fits in one place. Most real products are not like that. A real product is often a handful of services, each in its own repo: a backend, a couple of internal services, a shared library, a frontend. The feature a user asks for rarely lands in just one of them.

That gap is where multi-repo AI agents get hard. An agent that is excellent inside one repo is not automatically any good across a product that spans several, because the hard part is not writing the code in each repo. It is coordinating a change that crosses the boundaries between them without breaking something on the far side.

Why the boundary is the hard part

Inside one repo, the compiler and the tests catch most mistakes. Across repos, they do not, because nothing compiles the whole product at once. A change to a shared contract, an API shape, an event, a database column other services read, is safe in the repo where you make it and dangerous in every repo that depends on it.

The classic failure looks like this. An agent renames a field in the backend, the backend tests pass, the PR merges, and a frontend in a different repo that parsed that field breaks in production. Nothing was wrong with the change locally. The problem was that the change had a reach beyond the repo it lived in, and no single repo's tests could see it. If you have read designing agent handoffs and contracts, this is the same lesson at the scale of a whole product: the interface between parts is where the risk concentrates.

Keep each unit of work inside one repo

The first and most useful discipline is to keep every task an agent picks up scoped to a single repo. A repo is a natural boundary: it has its own build, its own tests, its own deploy. A task that stays inside one of them is a task you can verify with that repo's own tooling and merge on its own schedule.

A feature that genuinely spans services does not become one giant cross-repo task. It becomes several single-repo tasks with an explicit relationship between them. The change to the provider is one task. The change to each consumer is another. Each is independently implementable and independently verifiable, which is exactly what an agent needs to work reliably. The cross-boundary complexity moves out of the individual task and into the plan that sequences them, which is where it belongs.

Sequence by dependency, provider first

Once a feature is split across repos, the order matters as much as the content. The rule is the same one careful humans have always used for coordinated releases: change the thing that is depended upon before the things that depend on it.

In practice that means provider before consumer. The service that owns a contract ships the new shape first, in a way that does not break the old callers, and only then do the consumers move to it. For pull requests, this is the familiar dependency order: backend, then shared library, then frontend, with each PR noting what it waits on ("Depends on #123") so no one merges a consumer before its provider is ready. Get the order wrong and you ship a consumer expecting a contract that does not exist yet, which is an outage with a clean git history.

Contract changes deserve special care in the ordering. Removing or renaming something is a two-step dance: add the new shape and migrate consumers onto it first, and only remove the old shape once nothing uses it. An agent that does not understand this will happily delete a field in one PR and break three services in others.

Give the agent visibility it cannot get locally

An agent editing a consumer repo has a blind spot: the contract it is coding against is defined in a different repo it may not be able to see. Left to guess, it will invent a plausible shape, and plausible-but-wrong is the expensive failure mode.

So the agent working on one side of a boundary needs the other side's interface in front of it: the provider's type definitions, API description, or event schema, supplied as context even though the agent only edits its own repo. This does not mean handing it every repo at once, which just buries the signal. It means giving each task the specific slice of the other repos it must be correct against. The task stays single-repo; the context is deliberately cross-repo.

Make the product boundary explicit

None of this works if "the product" is only an idea in someone's head. Write it down. Which repos make up the product, who owns each, and where the contracts between them live. That definition is what lets you reason about reach at all: without it, you cannot know which consumers a given contract change will touch, and you are back to finding out in production.

An explicit product boundary also tells you where verification has to cross repos. Contract tests, checks that a provider still satisfies what its consumers expect, are the safety net that a single repo's tests cannot provide. They are the multi-repo equivalent of the tests you would demand inside one codebase, and they are worth the effort precisely because the boundary is where the compiler stops helping.

Where scale and coordination meet

Coordinating across repos also multiplies the operational load: more repos means more concurrent work, more PRs in flight, more rate-limited calls against the model and the git host. The mechanics of keeping that from overwhelming you belong with concurrency and rate limits at scale, but it is worth flagging here, because a multi-repo plan that ignores throughput stalls the moment more than a couple of services are in motion at once.

The honest limitation

Coordinating agents across repos reduces cross-boundary surprises. It does not eliminate them. Contract visibility is only as good as the contracts you actually publish, and a lot of real coupling is implicit: a consumer that depends on undocumented behavior, a shared database that no schema captures, an ordering assumption nobody wrote down. Static analysis of interfaces misses runtime coupling, and no amount of sequencing saves you from a dependency you did not know existed.

The sequencing itself is also a judgment call that stays human. Deciding that a contract change is safe, that consumers can be migrated in a given order, and that a particular split is correct, are product and architecture decisions, not mechanical ones. Tooling can surface the dependencies and enforce the order once you have chosen it. It cannot choose it for you, and pretending otherwise is how a confident plan ships a coordinated outage.

This is a stance we took seriously in building Loopsfinity: a product owns many repos, and every unit of work is scoped to a single repo by construction, so cross-service features become linked, ordered pieces rather than one sprawling change. The details of how we coordinate across those boundaries are ours, but the principle is not, and it is the one that keeps a multi-repo agent from turning a small change into a distributed incident. The wider system view is in AI agent architecture.