Skip to content

Course · Claude Code · Rules & memory

Layer CLAUDE.md across user, project, and subdirectory scopes

A CLAUDE.md is a file of standing instructions that Claude Code loads into the model’s context. Its scope is the location it lives at, and the location decides who receives its rules: every project on your machine, everyone who clones this repo, only you in this repo, or only sessions that work inside one subtree. Different rules want different audiences, and one file cannot serve them all.

Three rules from a small TypeScript payments service (the example this course returns to; each page restates the facts it needs) make the problem concrete:

  • processPayment’s idempotency key is optional - never assume a caller sends one. This is project truth: processPayment in src/payments/processor.ts declares idempotencyKey?: string, so a caller can omit it and get no duplicate check. Every teammate’s agent should carry this line.
  • Show me your plan before you edit. This is your habit, in every repo you open. Your teammates run looser, and your preference has no business in their sessions.
  • The ledger is in-memory; balances reset on restart. True of src/payments/ledger.ts, and relevant only when the agent is working inside src/payments/.

The scope ladder gives each of those three the right audience.

CLAUDE.md files live at several locations, each with a different reach. In the order Claude loads them, widest scope first, most specific last:

Managed policy OS-specific managed path (org-wide, IT-deployed)
User ~/.claude/CLAUDE.md (you, every project)
Project ./CLAUDE.md or ./.claude/CLAUDE.md (team, this repo)
Local ./CLAUDE.local.md (you, this repo only - gitignore it)
Subdirectory ./src/payments/CLAUDE.md (team, this subtree - proposal; loads on demand)

One line there names a file that does not exist: the example repo has no src/payments/CLAUDE.md. This lesson proposes one to show the mechanism, and because the in-memory-ledger note is a genuine candidate for it, though at this repo’s size the project file covers the ground. The other four scopes:

  • Managed policy: org-wide instructions your platform team deploys to an OS-specific path. You cannot override or exclude them, which is why a company standard survives a local file. Most engineers never write one.
  • User (~/.claude/CLAUDE.md): personal habits across all projects. The show-me-your-plan preference goes here. It follows you between repos and never lands in a teammate’s checkout.
  • Project (./CLAUDE.md or ./.claude/CLAUDE.md): the team-shared truth for this repo, committed to git. The payments service’s file lives here, and the optional-key rule joins it. Most rules land here.
  • Local (./CLAUDE.local.md): your personal notes for this one project, kept out of git: your scratch workflow, your local overrides. Add it to .gitignore so it never ships to a teammate.

The exact managed-policy paths differ by operating system, so take them from the memory reference rather than hardcoding one platform’s.

The part people get wrong: these files do not override each other. Claude Code loads the user file plus every CLAUDE.md and CLAUDE.local.md it finds from the filesystem root down to your working directory, and concatenates them all into one combined context. Launched at the payments repo root, that means the user file and the project file. Launched from a nested directory, each ancestor’s file joins too. None cancels another.

Order matters without being winner-takes-all. Content is laid out broadest to most specific; the file closest to where you launched is read last. Within a single directory, CLAUDE.local.md is appended after CLAUDE.md, so your personal notes are the final word at that level.

The practical upshot: a more specific instruction sits later in context and tends to win attention when two rules brush the same topic. Flatly contradictory guidance is another matter. Claude may simply pick one. That is not a feature to lean on; it is a reason to keep layers consistent and to prune contradictions whenever you audit the files.

The layers you will actually use stack like this, each concatenated onto the last, none replacing the one above it:

~/.claude/CLAUDE.md your rules (loaded first, every project)
|
| + concatenated, not overridden
v
repo-root/CLAUDE.md the team's rules (added next, this repo)
|
| + concatenated, not overridden
v
repo-root/src/payments/CLAUDE.md subdirectory rules (proposed; read last, on demand)
result: one combined context = user + project + subdirectory, all present at once

Subdirectory files differ in when they load. Files at or above your working directory load in full at launch. A file below it, such as the proposed src/payments/CLAUDE.md, is pulled in on demand, when Claude reads a file in that subtree. That is what makes per-subsystem rules cheap: the payments rules cost nothing until the agent goes there.

Rules can also live as topic files under .claude/rules/, one markdown file per topic. A file with paths: frontmatter, a list of glob patterns, loads only when Claude works with matching files. A file without it loads at launch, like .claude/CLAUDE.md. Both are ways to keep the root file short while a subsystem’s rules stay close to the code they describe. The memory reference documents both forms.

The resolver below runs the same question across a generic monorepo scenario: a root rules file, a nested one in packages/api/, and a path-scoped rule. It models four tools (Claude Code, Codex, OpenCode, and Pi), so use the Claude Code tab for this course and the others for contrast. Pick a working location and watch which files enter the window:

The agent is working on:

Additive - every applicable file loads; more specific guidance sits later and tends to draw more attention, but a flat contradiction is not a reliable override - Claude may pick either.

  1. #1 loaded~/.claude/CLAUDE.mdUser-wide; applies to every project.
  2. #2 loadedCLAUDE.mdProject root; always loaded.
  3. skippedpackages/api/CLAUDE.mdNested files load only when the agent touches files in that subtree.
  4. skipped.claude/rules/api-validation.mdpaths: ["packages/api/**"] - no match for this file.
Two files load, additively. The project file sits later in context and tends to draw more attention - but where the two flatly contradict, Claude may simply pick one. Keep the layers consistent.

The Claude Code answer, in prose: working on a file at the root, the user-wide file and the project root file load. Working on a file in packages/api/, the nested file joins them, and the path-scoped rule joins when its paths: pattern matches the file being read. Working in packages/web/, only the two always-on files load. Nothing replaces the root file.

Rules are one row of a larger map. The same project-versus-home split decides where skills (task playbooks), subagents, settings, and MCP servers (external tool connections) live. Hold the whole layout in your head once and you stop hunting for it. Walk it file by file (the other tabs show how the neighboring tools draw the same line):

committedin git, shared with your teamgitignoredlocal only, never sharedauto-generatedwritten by the tool; do not hand-edit
your-project/
~ (home directory)
Select a file or folder

Every entry shows what the file does, when Claude Code reads it, whether it belongs in git, and a working example.

You now have the full map of human-authored rules: what to write, where to put it, how the layers combine. Every rule on this page has had one author, you. The second persistence system has the agent writing the notes itself, and it fills a gap the hand-written files cannot. That is auto memory.