Your AI Coding Agent Doesn't Know Your Other Repos Exist

Multi-repo is the right architecture. The tooling just hasn't caught up.

Most non-trivial systems live across multiple repositories. A React frontend, a FastAPI backend, a worker process handling async jobs. Maybe an event-driven container or two. Maybe a core library with the shared database layer and API interfaces. Each one is its own git repo with its own CI pipeline, its own deploy target, its own reason for existing.

This isn't an accident. It's a deliberate architectural choice. Each repo represents an independently deployable unit with clear boundaries. The frontend doesn't need to know how the worker retries failed jobs. The backend doesn't care which bundler the frontend uses. Separation of repositories reflects separation of concerns, and that separation is load-bearing. It's how I think about the system, and it's how most teams I've seen organize anything beyond a single-service application.

The mono-repo crowd has good arguments. Single version of truth, atomic cross-cutting commits, unified CI. For some teams and some systems, that's the right call. But when you collapse independent services into one repository, you lose something important: the enforced discipline of treating each service as its own thing. Dependencies become implicit. Deployment boundaries blur. The mental model that says "this system stands on its own" gets eroded by convenience.

So I keep my repos separate. And then I open Claude Code, and the problems start.


Claude Code sees one repo at a time. When I'm working in the backend, it has full context: file structure, existing patterns, test conventions, the whole picture. It writes good code because it understands the codebase it's working in. But it has zero awareness that the backend's response schemas are consumed by the frontend, that the worker depends on the same database models, that the core library defines shared types used across three other repos.

This is the fundamental tension. The architecture that makes the system well-organized makes the AI agent partially blind.

It shows up in specific, predictable ways.


Contract breakage is the big one. I change a response schema in the API, and Claude Code builds it cleanly: tests pass, types are consistent, the code is solid within that repo. Meanwhile, the frontend is still expecting the old shape. The worker is still parsing the old event payload.

No single instance is dramatic. You update a response shape, you test in staging, the frontend breaks, you go fix it. Twenty minutes. But it happens on nearly every cross-cutting change, and Claude rarely warns you. If you're lucky, there's a note buried in the output log or the task summary mentioning that consumers may need updates. Realistically, you find out when something breaks in staging or dev, then context-switch back to the other repo to make the corresponding change. The cost isn't one spectacular failure. It's a constant background tax on every feature that touches more than one service, and it compounds when you're moving fast across a multi-repo system.

Planning drift is a different version of the same blindness. When I'm scoping a feature that touches multiple repos, I need to reason about ordering. The core library change goes first because the backend and worker both depend on it. The backend change goes next because the frontend consumes its API. The frontend change goes last. That dependency chain matters for development order, for PR sequencing, for deployment. But if I'm working repo by repo with an agent that doesn't see the graph, I'm the only one tracking those dependencies. The agent will happily start building the frontend integration against an API contract that hasn't been implemented yet.

Convention drift is slower but just as corrosive. Over weeks of development, each repo develops its own patterns independently. Error handling conventions diverge. Logging formats split. Config file structures that started identical drift apart because the agent in each repo optimizes locally without awareness of the cross-repo standard. Six months later you realize your repos feel like they were built by six different teams, because in a sense they were.


The obvious response is "just use a mono-repo." I get it. If the agent could see everything, it wouldn't have these blind spots. But that trades one set of problems for another, and the problems you get are worse if you value independent deployability.

In a mono-repo, the agent can see everything, but it can also touch everything. A task scoped to the API can accidentally modify a shared utility that breaks the worker. Deployment boundaries that were enforced by repo separation are now just conventions, which means they're suggestions, which means the agent will cross them. You've solved the visibility problem by removing the walls, and now you need a different kind of enforcement to keep the agent from wandering into rooms it shouldn't be in.

I'd rather keep the walls and give the agent a map.


That's what PairCoder's workspace system does. It sits above the individual repos and gives Claude Code structural awareness of the full system without collapsing everything into a single codebase.

The config is a YAML file at the workspace root:

name: my-platform
projects:
  core:
    path: ./core
    consumers:
      - backend
      - worker
  backend:
    path: ./services/api
    consumes:
      - core
    consumers:
      - frontend
  worker:
    path: ./services/worker
    consumes:
      - core
  frontend:
    path: ./frontend
    consumes:
      - backend

That's it. Project paths, and a dependency graph declared in consumers and consumes fields. The workspace root is just a parent directory; it doesn't need to be a git repo itself. Each project stays in its own repo with its own .git, its own .paircoder config, its own independent lifecycle.

But now the system knows the shape of the whole thing. And that knowledge propagates.


When I initialize a new project inside the workspace, PairCoder reads conventions from sibling repos and applies them as defaults. If the backend and worker both use pytest with 80% coverage targets, the new service inherits those settings automatically. If every sibling uses main as the default branch, the new project does too. Convention inheritance isn't magic. It's just reading existing .paircoder/config.yaml files from siblings and merging the common patterns. First-sibling-wins for simple settings, majority-wins for things like branch names, union for exclusion lists.

The discovery system validates that every declared project actually exists on disk, is a git repo, has PairCoder initialized, and reports the current branch and dirty state. bpsai-pair workspace status gives me a single view across all repos. Which ones have uncommitted changes. Which ones are on a feature branch while others are still on main. Before workspace, I'd check this manually, or more often, I wouldn't check at all and discover the inconsistency later.

bpsai-pair workspace pull updates every project in one command, skipping dirty repos with a warning instead of silently overwriting. Small thing. Saves a lot of terminal tabs.


The contract detection is where the cross-repo awareness pays for itself.

The ContractDetector watches for changes to files that look like contracts: anything with "schema," "route," "endpoint," or "command" in the path, plus config files in YAML or JSON. When it finds changes since a given commit, it classifies them by type (schema change, route change, command change, config change) and maps them to affected consumers using the dependency graph from the workspace config.

The ImpactAnalyzer takes those contract changes and produces an impact report: which repos are affected, what the severity is, and what actions to take. A schema change in the backend that has two consumers generates two action items. Not "maybe check other repos." Specific, directed: "Update frontend to match new schema from backend." "Update worker to match new schema from backend."

This is the part that used to live entirely in my head. I'd change a schema and mentally trace the dependency graph to figure out what else needed updating. Sometimes I'd catch everything. Sometimes I'd miss the worker because I was focused on the frontend. The workspace system externalizes that mental dependency tracking into something deterministic.


Planning a cross-repo feature used to mean a whiteboard session. Which repos does this touch? What order do the changes need to happen in? Which tasks block which? I'd work this out manually, then translate it into Trello cards that I had to keep in sync across boards.

The workspace orchestrator automates the mechanical parts. analyze_scope scans a feature description for project name mentions and automatically includes their consumers from the dependency graph. plan_tasks generates a CrossRepoTask per affected repo with token estimates, model recommendations, and explicit depends_on chains. The execution plan sorts these into parallelizable phases using topological ordering, then pushes .task.md files directly into each sibling repo's .paircoder/tasks/ directory.

The feature description is mine. The review of the generated plan is mine. But the dependency tracing, scope estimation, and sequencing happen from the workspace config instead of from my memory of which repos talk to which.


There's a distinction here that matters to me. The mono-repo approach solves visibility by eliminating boundaries. The workspace approach preserves boundaries and adds a coordination layer on top. The agent working in the API still only writes to the API. But it knows the API has consumers, knows what contracts it exposes, knows what will break if those contracts change. Awareness without access.

The permission system defines this concretely. Navigator agents are mapped to read-only permission modes for cross-repo planning. Driver agents get write-capable modes scoped to their assigned project. Reviewers stay read-only with audit logging. These mappings flow through Claude Code's own permission modes rather than a custom access-control layer, but the intent is the same: the workspace knows about all the repos, individual agents stay focused on theirs, and coordination happens through the workspace layer rather than through agents reaching across repository boundaries.


I still think multi-repo is the right default for distributed systems where independent deployment matters. The codebase I work in every day has repos that deploy on completely different schedules to completely different infrastructure. The backend runs on Azure. The worker deploys as a Function App. The frontend ships to a CDN. Combining them into a single repo would mean every deploy pipeline runs on every commit, or you build a complex path-based filtering system that reimplements the separation you already had.

The problem was never the architecture. It was that the tooling assumed a single-repo world. AI coding agents inherited that assumption because they inherited the IDE's context model: one project open, one set of files visible, everything else invisible.

Workspace gives the agent a system-level view without asking you to reorganize your code to fit the tool's limitations. Your repos stay independent. Your deploy pipelines stay separate. Your mental model stays intact. The agent just gets a map of how the pieces connect.

That's the right layer to solve this at.