Multi-Repo Workspaces Break Claude Code. Here's the Fix.
You have 5 repos in one workspace. Each has its own conventions. A single CLAUDE.md is the wrong shape. Per-repo storage with a workspace root is the pattern that actually scales.
Most Claude Code tutorials assume one repo per workspace. You open the editor, you’re in a repo, the repo has a CLAUDE.md, the agent reads it, you work. Clean.
Real projects don’t look like that.
My workspace has 58 repos in it. Not because I’m building a monorepo (I’m not), but because the product I work on is split across multiple services and client SDKs, plus example repos, plus docs, plus landing pages. When I open Claude Code at the workspace root, the agent has 58 different places to look for context, and no single CLAUDE.md can describe all of them.
This is the multi-repo workspace problem, and it breaks Claude Code in a specific way that most users hit within a month and never fully fix.
What breaks, concretely
You open Claude Code at your workspace root. You say “fix the flaky test in service-a.” The agent reads the workspace CLAUDE.md (if you have one) and starts working. Here is what fails:
Conflicting conventions. service-a uses pnpm, service-b uses npm, service-c is in Go and has nothing to do with the JS debate. Your workspace CLAUDE.md has to either pick one (and be wrong for the others) or list all three (and confuse the agent about which applies when).
Per-repo decisions get lost. You decided in service-b to migrate from Joi to Zod. That decision lives… where? In workspace CLAUDE.md? Then it contaminates service-a (which still uses Joi because it’s an older service). In service-b/CLAUDE.md? Then it doesn’t get loaded when you cross into service-b from workspace root.
Safety rules can’t be scoped. You want “never push to main” for service-a (production), but for example-repo it doesn’t matter because that repo has one developer and no branch protection. If safety rules live at workspace level, they’re too strict. If they live at repo level, you need to know which repo you’re in, and Claude Code’s default mode doesn’t fully track that.
Session handoffs span repos. You start a session touching service-a. You fix the test, commit. Then you notice the fix requires a corresponding SDK change in sdk-typescript. You switch. Now your session crosses two repos, and when you stop, the handoff should land somewhere that makes sense for both.
Glossary drifts. The word “intent” means one thing in service-a (a domain object) and another in docs (a user-facing concept). The agent sees “intent” in your current sentence and doesn’t know which meaning to use.
These are not hypothetical. I hit every one of these in the first two weeks of running Claude Code on a 50+ repo workspace.
The wrong fix: one big CLAUDE.md
My first attempt was to write a workspace-level CLAUDE.md that described every repo’s conventions as a separate section:
# Workspace
This workspace has 58 repos. Conventions differ per repo. See below.
## service-a (Python)
- uses Postgres, pytest, ruff
- deploy via deploy-prod.yml
- never push to main
## service-b (TypeScript)
- uses Zod, not Joi
- deploy via Vercel
- uses pnpm
## sdk-typescript
- uses npm (not pnpm), for compatibility with downstream
- release via release.sh
- ...
This grew to 300 lines within a week. It had problems:
- The agent had to read all 300 lines every time to find the 5 lines relevant to its current task.
- When it was working in
service-a, the conventions ofsdk-typescriptleaked into its context and it occasionally applied the wrong rule. - I couldn’t version-control the conventions alongside the code they applied to, because they all lived in a file at workspace root that wasn’t inside any repo.
The actual fix: per-repo storage with workspace awareness
What works is this shape:
- Each repo has its own context store in
.axme-code/at its root. - The workspace also has its own
.axme-code/at workspace root, for workspace-level context. - When the agent works in a repo, it loads that repo’s context plus the workspace context.
- When the agent crosses a repo boundary, it notices and reloads.
This is how AXME Code works, but you could build the same pattern with plain files and a few hooks. Let me walk through what it looks like in practice.
Repo layout
~/workspace/
├── .axme-code/ # workspace-level context
│ ├── oracle/ # workspace metadata (list of repos, links)
│ └── memory/
│ └── cross_repo_patterns.md
├── service-a/
│ ├── .axme-code/ # service-a's own context
│ │ ├── oracle/stack.md # "Python, pytest, Postgres"
│ │ ├── memory/
│ │ ├── decisions/
│ │ └── safety/
│ └── src/
├── service-b/
│ ├── .axme-code/ # service-b's own context (different stack)
│ └── src/
└── sdk-typescript/
├── .axme-code/ # sdk's own context (different conventions)
└── src/
Each repo is self-contained. Every repo’s .axme-code/ describes that repo and nothing else. Conventions that apply to multiple repos live at workspace level, but the default assumption is that each repo has its own rules.
Loading
When the agent starts working in a particular repo, it:
- Detects the repo root by walking up from the current working directory until it finds
.axme-code/or.git/. - Loads context from that repo’s
.axme-code/. - Also loads context from the workspace-level
.axme-code/(if it exists), but treats workspace context as lower-priority. Repo-level rules win conflicts. - Caches this until the agent crosses a repo boundary.
Crossing a boundary means: the agent’s next action is in a different repo than the last one. This is detectable because the path is different. When it happens, the old context is unloaded and the new repo’s context is loaded.
Storage decisions
- User facts live globally in
~/.config/axme-code/user.md. They apply to every repo. - Project patterns, decisions, safety live in
<repo>/.axme-code/. Scoped to that repo. - Cross-repo patterns live in
<workspace>/.axme-code/memory/cross_repo_patterns.md. Things that are true everywhere: “contact email iscontact@axme.ai,” “we license everything MIT,” etc. - Session handoffs are scoped to the repo you were mostly working in. If your session crossed repos, the handoff notes which ones and includes pointers to each repo’s relevant files.
What this gives you
The key properties:
A session that touches only one repo sees only that repo’s context. The agent isn’t confused by service-b’s rules when working in service-a.
A session that touches multiple repos sees the union, but weighted. The agent knows which repo it’s in right now and applies that repo’s rules first. Other repo contexts are available if it asks.
Conventions are version-controlled alongside the code they describe. When service-a changes its conventions (e.g., migrates from Joi to Zod), the decision goes into service-a/.axme-code/decisions/, committed with the code change. Anyone checking out that commit sees the corresponding convention.
The workspace-level context stays small. Most things belong at repo level. The workspace-level context is for cross-cutting concerns only (contact email, license, shared CI rules).
What doesn’t work yet
Honest caveats:
-
The boundary detection is heuristic. The agent guesses which repo it’s working in based on file paths and recent commands. If you jump abruptly from one repo to another mid-sentence, the guess can be wrong. In practice this is rare.
-
You need to set up
.axme-code/in every repo. For a new repo, run the setup once. Takes 30 seconds. For 50 existing repos, the first-time setup is annoying, but it’s a one-time cost. -
Cross-repo refactors are still hard. If you are renaming a type across 5 repos, the agent needs to maintain consistent context across all of them simultaneously. The per-repo storage helps but does not completely solve this. You still need to tell the agent up front “we’re doing this across these 5 repos” and let it track the state manually.
-
Safety rules cannot be inherited downward. If you want workspace-level safety (“never force push on any repo”), you have to replicate it in each repo’s safety rules, or maintain it as workspace-level. I do the latter, but it’s slightly more fragile.
The minimum version
If you want to try this without installing anything:
- In each of your repos, create
.agent-context/(name doesn’t matter, pick one). - Put a one-page markdown file in each with that repo’s stack, entry points, and gotchas.
- In each session, tell the agent: “we are working in
<repo-name>, read.agent-context/before anything else.” - See if it feels better than workspace-level
CLAUDE.md.
It will. The scoping alone is most of the value. The automation (per-repo storage, automatic loading, audit-driven updates) is nice to have but the insight is the shape: convention lives with the code, not above it.
If you’re running Claude Code on more than two repos, stop fighting workspace-level CLAUDE.md. Move context into the repo where it belongs. Everything else follows.