I let Claude loose in a 60-package monorepo. Here is the leash.
How I scope Claude Code to one package, rebuild only what changed, and review across boundaries before anything merges.
The first time I handed Claude Code a ticket in our monorepo, it did the right thing in completely the wrong place. The task was a tiny fix to a date helper in one package. Claude found a similar helper three packages over, decided that one was nicer, and started refactoring both to share a util. Reasonable instinct for a greenfield repo. In a workspace where 40 people push and the build graph has opinions, that is how you turn a 3 line PR into a cross-team incident.
So I stopped trying to make the model smarter and started making the environment narrower. The build I am sharing here, Monorepo Orchestra, is less a clever prompt and more a set of guardrails: keep edits inside one package, rebuild only what the change actually touches, and never let a diff cross a boundary without someone looking at the seam. It runs on Claude Opus 4.8 because the planning step is where most of the value is, and Opus is the one I trust to read the dependency graph and not panic.
The rules that matter
My CLAUDE.md is short on purpose. Long memory files get skimmed, same as long onboarding docs. I keep it to the three things that actually cause damage when they go wrong.
# Workspace rules (Nx monorepo, ~60 packages)
## Package boundaries
- Respect package boundaries. Code lives in exactly one package.
- Import only across boundaries declared in the dependency graph.
- No circular dependencies. If a fix "wants" a cycle, stop and ask.
## Builds and tests
- Only rebuild affected projects. Never run a full `nx run-many`.
- Use `nx affected` against the merge base for build/test/lint.
## When in doubt
- Map the blast radius FIRST (run the dependency-mapper agent).
- A change that touches 2+ packages is a design decision, not a chore.
Surface it. Do not silently refactor a shared util.Four subagents, one job each
I run four subagents and resist the urge to add a fifth every week. dependency-mapper goes first and answers one question: if I touch this file, what breaks. package-owner makes sure edits stay inside the package that owns the code. integration-tester checks the seams between packages, because that is where monorepo bugs actually hide. reviewer reads the final cross-package diff like a grumpy teammate. Here is the mapper, which is the one that earns its keep.
---
name: dependency-mapper
description: >
Use BEFORE editing anything. Maps the blast radius of a change:
which packages depend on the file/package being touched, and what
rebuilds. Read-only. Returns affected package list + risk notes.
tools: Bash, Read, Grep
model: claude-opus-4-8
---
You map impact, you never edit.
1. Identify the package that owns the target file.
2. Run `nx graph --file=/tmp/graph.json` and read the reverse deps.
3. Run `nx affected:graph --base=origin/main --files=<changed>` to see
what build/test would re-run.
4. Report:
- owning package
- direct + transitive dependents (the blast radius)
- whether any boundary would be crossed by the proposed change
- a one-line risk verdict: contained | crosses-boundary | cycle-risk
Stop after the report. Do not propose code. The main agent decides.Hooks do the boring enforcement
Rules in a markdown file are suggestions. Hooks are law, because the harness runs them whether the model feels like it or not. I lean on three. A PreToolUse hook scopes every write to the package the task is about and blocks edits that wander outside it. A PostToolUse hook runs the affected build and test, never the whole graph. And a Stop hook prints the cross-package diff so nothing crosses a seam silently.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "scripts/scope-to-package.sh \"$CLAUDE_TOOL_FILE_PATH\""
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "nx affected -t build test --base=origin/main"
}
]
}
],
"Stop": [
{
"type": "command",
"command": "git diff --stat origin/main -- packages/ | scripts/cross-package-diff.sh"
}
]
}
}The affected-only build is the part people underestimate. Our full graph takes about nine minutes to build and test. nx affected on a single-package change usually settles in well under a minute. When the agent runs that loop after every edit instead of once at the end, it catches the break while it still remembers why it made the change. That tight feedback is most of why this build lands at a 3.3s median step and an 87% pass rate without me babysitting it.
| Piece | What it does | Why it is in the build |
|---|---|---|
| Opus 4.8 | Plans the change, reads the graph | Planning over a big graph is where a weaker model flails |
| dependency-mapper | Blast radius, read-only | Stops the silent cross-package refactor |
| scope-to-package hook | Rejects out-of-package writes | Law, not a suggestion |
| nx affected hook | Builds and tests only what changed | Fast loop, catches breaks in context |
| cross-package diff on Stop | Flags any seam the change touches | I review boundaries, not every line |
Where Sentry and postgres earn their slots
Two of my MCP servers are not about editing at all. The postgres server lets the integration-tester check a migration against a real schema instead of guessing column names, which matters when a single package owns the migrations everyone else reads from. The sentry server gives the reviewer a way to ask whether the file it is about to change is already throwing in production. A reviewer that knows a function is currently on fire prioritizes very differently from one reading cold code. github and filesystem are the obvious two, so I will not bore you.
26:11If you only watch one thing before copying my setup, watch that. A lot of what I do with boundaries and affected builds is just the explore-plan-code-commit loop applied to a repo that punishes you for skipping the explore step. The official subagents docs are also worth a slow read, because the isolated-context-per-agent model is the whole reason four small agents beat one big prompt here.
Create custom subagents - Claude Code DocsThe reference I keep open when tuning agent frontmatter, tool allowlists and per-agent context.code.claude.comdisler/claude-code-hooks-masteryEvery hook lifecycle event with working examples. My scope-to-package and cross-package-diff scripts started as forks of these.disler/claude-code-hooks-mastery4.2kHonest about the limits
- It assumes Nx or Turborepo. If your affected-graph command is wrong, the fast loop becomes a slow lie and you will trust green builds that did not test the right thing.
- Big architectural changes that genuinely span packages still need a human in the plan. The build is tuned to refuse those, not to do them well.
- The PreToolUse hook can be annoying on legitimate multi-package work. I keep a flag to relax it, and I am honest with myself about how often I reach for it.
I am not trying to make Claude an architect. I want it to be the best mid-level engineer on a team with strong conventions: fast, scoped, and quick to ask before it does something clever across a boundary. After two months on this setup our agent-authored PRs stopped being the ones I dreaded reviewing. They touch one package, the affected suite is green, and the cross-package diff is empty. That is the whole pitch.
If you want to try it, grab the build from Setuproll and run npx setuproll add claude-code-monorepo-orchestra, then point the affected commands at your own workspace and trim the CLAUDE.md to your three worst footguns. Steal the hooks, keep the boundaries honest, and tell me what breaks.