One root CLAUDE.md covering every package either grows until it's mostly noise, or stays generic enough to be useless. Claude Code has native support for splitting instructions, commands and skills by directory, so a session working in packages/api/ never loads the frontend's conventions.
Claude Code loads every CLAUDE.md from your working directory and each parent directory at launch. Files in subdirectories below that load on demand, the first time Claude reads a file in that directory.
monorepo/
CLAUDE.md # rules that apply everywhere
packages/
api/
CLAUDE.md # API-specific conventions
.claude/skills/
web/
CLAUDE.md # frontend-specific conventions
.claude/skills/
shared/
CLAUDE.md
Root CLAUDE.md holds repo-wide rules:
Run package scripts from the package directory, not the monorepo root.
Prefix commit subjects with the package name, e.g. `api: add rate limiting`.
Never edit files under packages/*/generated/. Run `npm run codegen` in the package instead.
Each package's own CLAUDE.md adds what only applies there, for example packages/api/CLAUDE.md:
Copy `.env.example` to `.env` before running anything. Tests fail without it.
Write queries with the Knex query builder. Never put raw SQL in route handlers.
See the CLAUDE.md template guide for what belongs in these files versus what to leave out.
| Start from | File access | CLAUDE.md loaded at launch |
|---|---|---|
| Repo root | Every file | Root only; package files load on demand as Claude reads there |
| A package directory | That subtree, until you grant more | That package's plus every ancestor's |
Run /context in a session and check Memory files to confirm which CLAUDE.md files actually loaded.
Don't try to make one root command work for every package. State the rule once at the root ("run scripts from the package directory") and let each package's CLAUDE.md list its own copy-pasteable commands:
## Commands (run from packages/api/)
- Dev: `npm run dev`
- Test one file: `npm test -- src/__tests__/routes/users.test.ts`
- Migrate: `npm run migrate`
A skill in packages/api/.claude/skills/ loads only when Claude works on files in that package. Frontend work never pulls in API testing conventions:
---
name: api-testing
description: Testing patterns for the API package. Use when writing or
modifying tests in packages/api/.
---
- All tests: `npm test`
- Single file: `npm test -- <path>`
- Wrap database tests in a transaction that rolls back.
To scope a skill by file pattern instead of location, put it in the repo root's .claude/skills/ and add a paths field to its frontmatter, e.g. paths: ["**/migrations/**"] for a migrations skill that should apply wherever that path shows up. If you start Claude from the repo root and it touches many packages in one session, skills from every package it visits accumulate, so keep descriptions short and lead with the words a request would actually contain. See the skills guide for description-writing tips.
Starting from the root means another team's CLAUDE.md loads the moment Claude reads a file there. Exclude packages you never touch with claudeMdExcludes in .claude/settings.local.json:
{
"claudeMdExcludes": [
"**/packages/legacy-*/**"
]
}
Going the other way, a task that spans packages, like updating a shared type used by both api and web, needs explicit access when you start from a single package directory. Grant it per-session with --add-dir, or commit it for the team in that package's .claude/settings.json:
{
"permissions": {
"additionalDirectories": ["../shared"]
}
}
See the settings.json guide for where these files live and how scopes layer. If a package also needs a PreToolUse hook, like blocking risky commands in a deploy package, the free hook builder is a fast way to write and test the matcher before committing it.
Keelwork bundles 10 workflow skills, 5 tested safety hooks (including a full guard-bash and a secret scanner), 3 subagents and 5 CLAUDE.md templates, with a one-command installer that safely merges into your settings.
Get Keelwork — $24 →