DEV Community

Ian Johnson
Ian Johnson

Posted on • Originally published at tacoda.Medium on

Scoping Rules: Global, Project, Path-Glob

A rule that fires on every file is a tax. A rule that never fires is dead code. The cost of getting scope wrong is paid every session, on every task, by every contributor and almost nobody talks about it.

I want to talk about it.

The three scopes in Claude Code are global (~/.claude/CLAUDE.md), project (./CLAUDE.md), and path-scoped (subdirectory CLAUDE.md, or feature docs loaded by path match). They look like a hierarchy. They behave like three different tools.

The default mistake is to put everything in the project CLAUDE.md and call it done. The file grows. It crosses 500 lines. It crosses 1,000. The agent reads it on every task, including the ones where 90% of the file is irrelevant. The team stops reading it because it is too long to absorb. The new contributor never reads it at all.

Tokens are the easy half of the cost. Attention is the harder one. Every line of CLAUDE.md is a line the agent has to weigh against every other line, and a line the human has to skip past when they are looking for the one rule they actually need.

Global: the rules that follow you

Global rules apply to every project on your machine. The bar is very high. If a rule does not survive the test would I want this in a Python repo, a TypeScript repo, and a shell-script repo, it does not belong in global.

What I keep there are personal preferences about how the agent should communicate. Be terse. Do not narrate intermediate reasoning. Do not add commentary to commit messages. Do not write documentation files unless I ask. None of those depend on the language, the framework, or the project. They are about the working relationship, not the code.

What does not belong in global: anything about a specific language, framework, library, or convention. Use functional components in React is a fine rule. It does not belong in global. The moment I open a backend repo, the rule is firing against code that does not have React in it. The agent has to either ignore it (wasted tokens) or get confused (worse).

If you cannot phrase the rule in language that applies equally to any repo, the rule is not global.

Project: the rules that define the codebase

Project rules apply to every file in the project. They are for conventions true everywhere in this codebase. Naming. Layout. Build commands. The library you use for X. The framework’s pitfalls.

The bar for a project rule is does this apply to most of the files in the repo. If the rule only applies to the frontend, or only the database layer, or only one feature, it does not belong at the project root. It belongs in a path-scoped file.

A good project rule: Use pnpm, not npm. Applies everywhere. Cheap for the agent to honor, cheap for a human to verify. Tests live in tests/, not __tests__/. Same shape. All public exports go through index.ts. Same shape.

A bad project rule, the one I see most often: When working in the API module, make sure the validation schema is updated to match. Applies to maybe 10% of the files. The agent reads it on every other task. It earns its keep one out of ten sessions; the other nine, it is noise.

That rule belongs in a subdirectory CLAUDE.md inside the API module, where it loads when the agent is touching files in that module and stays silent when it is not.

Path-scoped: the rules that earn their keep

Path-scoped rules are the underused primitive. Most teams know they exist and do not use them, because the project root is the path of least resistance and I will move it later is the path of I will never move it.

The mental model is simple. The agent loads context based on what it is looking at. Edit a file in src/components/, the CLAUDE.md in src/components/ loads. Edit a file in src/api/, the CLAUDE.md in src/api/ loads. Rules that are only true for that subtree go there.

The discipline pays off three ways.

The agent’s context window is smaller on every task. The rules it loads are the rules that apply. Nothing else.

The rules themselves can be specific. A rule that only fires inside src/api/ does not have to caveat itself. It does not have to say in the API module, do X. It just says do X, because the file location is doing the scoping. The rule reads more directly. The agent applies it more reliably.

The rules are colocated with the code they constrain. A new contributor opening src/api/ sees the rules for that module right there. The convention is documented where the convention lives.

The test for moving a rule down

The quick check I run on every rule in the project root: would this rule still apply if I deleted half the repo? If the answer is no, the rule is mis-scoped. It is pretending to be a project rule when it is a module rule.

The fix is to find the narrowest directory that contains every file the rule applies to, and move the rule there. Sometimes that directory is the project root, and the rule stays. More often it is two or three levels down, and the rule moves with it.

The move is rarely complex. Cut three lines from CLAUDE.md at the root, paste them into a new CLAUDE.md inside the relevant directory, commit. The agent’s behavior does not change on tasks that touched files in that directory. The agent’s behavior does change on tasks that did not, because the rule is no longer firing where it was not needed.

That second effect is the whole point.

Audit your project root this weekend

Open your project CLAUDE.md. Walk each rule. Ask the delete half the repo question. Move the ones that fail down to the narrowest directory that owns them.

The first audit usually moves four or five rules. The root file gets shorter. The subdirectories get a CLAUDE.md they did not have before, and the conventions of each module become legible to the next person who opens it.

The harness is not the file at the root. It is the tree.

Top comments (0)