Claude Code in a Monorepo: How to Keep an Agent From Getting Lost

David IyaDavid Iya August 16, 2026 9 min read
A wooden library card catalog with many labelled drawers, one drawer pulled open beside a closed laptop
Original image, Claude Code Club

The Short Answer

To use Claude Code in a monorepo, scope each session to one package instead of the repo root. Start the session in the package directory, keep a short CLAUDE.md in that package describing its build, test, and run commands, and state the boundary in the request itself: this package only, and tell me before you touch anything outside it. A root-level session with a vague request is what produces edits scattered across packages you did not mean to open.

Why a Monorepo Breaks an Agent's Sense of Scope

A monorepo is many projects sharing one root. Human developers hold the boundaries in their head: this change belongs to the web app, that helper lives in the shared package, the mobile client is not part of this task. None of that is written down anywhere the agent can read, so when you open a session at the root and ask for a fix, the agent sees one enormous project with no internal walls.

What follows is not a hallucination. It is a reasonable reading of an unreasonable request. You ask it to rename a field. It finds that field in the shared types package, updates it there, then updates the three apps that import it, then updates a test fixture in a fourth package you forgot existed. Every individual edit is correct. The change as a whole is now far larger than the one you agreed to review.

  • The blast radius grows silently. In a single-package repo you can read the whole diff. In a monorepo the diff spans packages owned by different people, and you stop reading carefully around file twelve.
  • The build feedback is slower. A cross-package change often will not fail until a downstream package builds, so the agent gets its signal late or not at all.
  • The conventions are not uniform. One package uses one test runner, another uses a different one, and a root-level instruction that is true for one is wrong for the other.
  • The context fills with the wrong things. Time spent reading unrelated packages is context not spent on the code you actually asked about.

The Package-Scoped Session - The Rule That Fixes Most of It

The package-scoped session is the working rule I use for every monorepo task: one session, one package, one stated boundary. Open the session inside the package directory rather than the repo root. Say which package you are in. Say explicitly that the agent should stop and tell you before editing anything outside it. That third sentence is the one people skip, and it is the one that does the work.

  1. Open in the package, not the root. Point the session at the directory that owns the change. The agent still has the machine, so it can read a sibling package when it genuinely needs to, but the default gravity is local.
  2. Name the package out loud in the request. 'In packages/billing, fix the proration rounding' beats 'fix the proration rounding' because the first sentence rules out the other twenty directories before the agent starts looking.
  3. State the boundary and the escape hatch. 'Do not edit files outside this package. If the fix requires a change in the shared package, stop and show me the plan first.' This turns a silent spread into a decision you get to make.
  4. Require the plan before the cross-package edit. When the agent comes back and says the change needs a shared type updated, you now have the useful conversation: is this actually a shared concern, or did we just leak a package detail into common code?

Give Every Package Its Own CLAUDE.md

A single CLAUDE.md at the repo root cannot describe a monorepo accurately, because the thing it most needs to describe - how you build, test, and run this code - is different per package. Keep the root file for what is genuinely global (the package manager, the commit conventions, the rule that the agent may not edit another package without asking) and put the specifics in a short CLAUDE.md inside each package.

What belongs at each level

LevelWhat goes hereWhat does not
Repo root CLAUDE.mdPackage manager and workspace layout, the boundary rule, commit and branch conventions, anything true everywherePer-package build or test commands, framework details that only one app uses
Package CLAUDE.mdHow to install, build, test, and run this package, its framework, its known sharp edges, what it may and may not importRestating global rules, long architecture essays that will go stale
The request itselfThe one task, the package name, and the boundary sentenceAnything you would have to retype every session - that belongs in a file

The most valuable line in a package CLAUDE.md is usually the import rule. Writing 'this package may import from the shared package but nothing else, and nothing may import from it' gives the agent the architectural constraint that lives in your head and nowhere in the code. It also makes bad suggestions self-evident, because a proposed import that violates the rule now reads as obviously wrong rather than as a judgment call.

Handling a Change That Genuinely Spans Packages

Some changes really do cross the wall, and the boundary rule is not there to stop them. It is there to make them deliberate. When the agent comes back with 'this needs a field added in the shared types package', treat it as three separate pieces of work rather than one, and run them in that order: change the shared package, verify it builds, then update each consumer.

  1. Do the shared change first, on its own, and get it building and tested before anything downstream touches it. A shared package that is half-changed makes every downstream error ambiguous.
  2. Update consumers one package at a time, in separate passes. The temptation is to let the agent sweep all of them in one go. That produces a diff nobody reviews properly.
  3. Verify at each stop. Run that package's own build and tests before you move to the next one, so a failure points at the package you just touched rather than at the whole tree.
  4. Keep the commits split by package where your workflow allows it. It makes the change reviewable by the people who own each piece, and it makes a revert surgical instead of catastrophic.

When to Run Separate Sessions Instead of One

If you have two unrelated tasks in two packages, run two sessions. It sounds obvious and almost nobody does it, because one session already has momentum. The cost of reusing it is that the context now carries the first task's files, decisions, and half-remembered constraints into the second task, and the second task inherits assumptions that were never true for it.

Separate sessions also give you a cleaner recovery. When something goes wrong in a monorepo, the first question is always which change caused it. Two sessions with two scopes and two sets of commits answers that in seconds. One long session that wandered through five packages turns it into an investigation.

Start With One Package This Week

Pick the package in your monorepo you change most often. Write it a CLAUDE.md with four things: install, build, test, and what it is allowed to import. Then run your next task as a package-scoped session with the boundary sentence included, and notice how differently the agent behaves when it has to ask permission to leave. Most people find the first thing it asks about is a shared change they would have merged without noticing.

Free Claude Code drops, straight to your inbox

Short, practical drops on skills, MCP, agents, prompts, and more. No spam, unsubscribe anytime.

Frequently asked questions

Can Claude Code handle a monorepo?

Yes, and it handles one well when the session is scoped to a package rather than the repo root. The difficulty in a monorepo is not size, it is that a root-level session treats every package as equally in scope, so a small request can spread. Open the session inside the package that owns the change, name that package in the request, and tell the agent to stop and ask before editing anything outside it.

Should CLAUDE.md live at the monorepo root or in each package?

Both, with a clear split. The root file holds what is true everywhere: the package manager, the workspace layout, commit conventions, and the rule that the agent may not cross a package boundary without asking. Each package gets a short file with its own install, build, test, and run commands plus what it is allowed to import. Build and test commands differ per package, so a root-only file will be wrong for most of them.

How do I stop Claude Code from editing other packages?

Say it in the request and repeat it in the root CLAUDE.md, and include an escape hatch rather than a flat ban. The wording that works is: do not edit files outside this package, and if the change requires one, stop and show me the plan first. A flat ban makes the agent work around the wall. An escape hatch turns the crossing into a decision you approve, which is the outcome you actually want.

What is the right way to make a change that spans several packages?

Split it into ordered passes rather than one sweep. Change the shared package first and get it building and tested on its own, then update each consumer in a separate pass, verifying each package's build before moving on. Splitting commits by package where you can makes the change reviewable by the people who own each piece and makes a revert precise instead of sweeping.

Is it better to use one long session or several short ones in a monorepo?

Several short ones, scoped per task and per package. A reused session carries the previous task's files and assumptions into the next one, and in a monorepo those assumptions are frequently wrong for a different package. Separate sessions also make it obvious which change caused a problem, because each scope maps to its own set of commits.

Last reviewed by David Iya on August 16, 2026

David Iya

Written by

David Iya

Forbes 30 Under 30 · Y Combinator

Keep reading

Ready to build it yourself?

Join Claude Code Club, the #1 community for learning claude code, for $9/month.

← Back to the blog