Configure CLAUDE.md files with appropriate hierarchy, scoping, and modular organization
CLAUDE.md files are the always-loaded memory that shapes how Claude Code behaves in a repository. Getting the hierarchy and scope right determines whether your whole team and CI actually receive the same standards, and organizing memory modularly keeps context lean instead of drowning every request in irrelevant rules. Most production problems here are scoping bugs (personal config that never reached teammates) or bloat (one giant file that dilutes attention), both of which are diagnosable and fixable.
The three-tier memory hierarchy
Claude Code assembles its instructions from plain-markdown memory files it discovers by location. Three tiers matter for this exam: user-level at ~/.claude/CLAUDE.md (applies to every project you open on this machine), project-level at the repo root ./CLAUDE.md or .claude/CLAUDE.md (shared with the whole team through version control), and directory-level CLAUDE.md files placed inside subdirectories (scoped to one package or folder).
When a session starts, Claude Code walks up the directory tree from your current working directory toward the filesystem root and loads every CLAUDE.md it finds, plus your user-level file. Directory-level files deeper in the tree are pulled in on demand when Claude reads or edits files in that subtree, so a packages/api/CLAUDE.md governs work inside packages/api without polluting unrelated packages.
All discovered files are combined into context. A separate enterprise managed policy file, if your organization deploys one, sits above everything and cannot be overridden; beyond that, treat the tiers as layered, with more specific files refining the broader ones. The single most testable consequence: only files committed to the repository reach your teammates and CI.
Scope: shared versus personal (the classic diagnostic)
The defining difference between the tiers is who sees them. ~/.claude/CLAUDE.md lives in your home directory, never enters the repository, and therefore never reaches teammates, pull-request automation, or CI runners. Project-level and directory-level files live in the repo, so cloning or pulling the repository is all it takes to receive them.
This produces the canonical exam diagnostic: a convention 'works on my machine' but a new team member's Claude ignores it. The cause is almost always that the instruction sits in your personal user-level file instead of a committed project file. The fix is to move it into ./CLAUDE.md (or a .claude/rules/ file) and commit it, not to reword the instruction.
Use user-level memory only for genuinely personal preferences (how you like responses phrased, editor habits) that should follow you across all projects and that no teammate needs. Anything the team must apply consistently belongs in project scope.
@import for modular composition
CLAUDE.md supports an @import syntax: writing @path/to/file inline pulls that file's contents into the memory context. Paths may be relative to the importing file or absolute, and ~ is allowed for home-directory paths. Imports can nest up to five levels deep, and an @-reference inside a code span or code fence is treated as literal text rather than an import.
This lets you keep a lean, readable root CLAUDE.md that composes focused standards files instead of duplicating them. In a monorepo you can give each package's CLAUDE.md only the imports its maintainer knows are relevant:
# packages/api/CLAUDE.md
@../../.claude/rules/api-conventions.md
@../../.claude/rules/testing.md
The payoff is a single source of truth: update testing.md once and every package that imports it stays in sync. Copy-pasting the same block into each file instead guarantees drift over time.
.claude/rules/ for topic-specific organization
When a root CLAUDE.md grows into hundreds of lines covering testing, API design, deployment, and more, it becomes hard to maintain and forces irrelevant context into every session. The modular alternative is the .claude/rules/ directory: split the monolith into focused topic files such as testing.md, api-conventions.md, and deployment.md.
These rule files are still version-controlled project configuration, so the team-sharing property is preserved. You can reference them from CLAUDE.md with @import, and (as covered in task 3.3) rule files can carry YAML frontmatter with a paths: glob field so a rule loads only when Claude edits matching files. For task 3.1 the key idea is purely organizational: many small, purpose-named files beat one sprawling document.
Think of .claude/rules/ as the organized layer of project memory. It complements CLAUDE.md rather than replacing the concept of committed, team-shared configuration.
/memory, /init, and the # shortcut
The /memory slash command is your inspection and editing tool. It shows which memory files are currently loaded and lets you open them for editing, which is exactly how you diagnose 'why does Claude behave differently in this session' or 'why is my rule not taking effect.' If a file you expected is absent from the list, you have found your scoping bug.
Two related mechanics: /init bootstraps a project by generating a starter CLAUDE.md from the codebase, and beginning a line of input with # quickly appends a note to a memory file without leaving the conversation.
Crucially, none of this involves a config.json commands array, an environment variable, or a hidden flag. Memory is just markdown discovered by location, and /memory is the reliable way to confirm what actually loaded.
Choosing the right home for an instruction
Deciding where an instruction lives is a design skill. Ask two questions: who needs it and when should it apply. If the whole team needs it always, it belongs in project-level CLAUDE.md (optionally split via .claude/rules/ and @import). If only you need it, user-level. If it applies only to one package, a directory-level CLAUDE.md. If it applies to a file type scattered across directories (for example all *.test.tsx), a path-scoped rule file is better than a directory CLAUDE.md (task 3.3).
Reserve CLAUDE.md for always-loaded, universal standards. On-demand, task-specific workflows belong in skills or slash commands (task 3.2), not in memory, because everything in CLAUDE.md consumes context on every single request. Being disciplined here keeps the always-on context small and the model's attention on what matters.
Anti-patterns to avoid
Why it fails: User-level memory is machine-local and never committed, so teammates, new hires, and CI runners never receive it. The behavior looks correct only on the machine where the file exists, producing inconsistent output across the team.
instead Commit the standards to project-level ./CLAUDE.md (or .claude/CLAUDE.md), so pulling the repo distributes them to everyone and to automation.
Why it fails: It loads irrelevant context into every session (wasting tokens and diluting attention), and it is hard to maintain as sections multiply and conflict.
instead Keep a lean root CLAUDE.md that @imports focused files, move topics into .claude/rules/ (testing.md, api-conventions.md, deployment.md), and use directory-level CLAUDE.md for package-specific rules.
Why it fails: Duplication drifts: a change must be made in many places, and files silently diverge, so different packages end up following different versions of the 'same' rule.
instead Keep one source file (e.g., .claude/rules/testing.md) and @import it into every package that needs it, giving you a single source of truth.
Why it fails: The real cause is frequently a configuration difference (a file loaded in one session but not another, or a personal-scope file present on one machine only), which you will never find by re-prompting.
instead Run /memory to confirm exactly which memory files loaded in each session, then correct the scope or location of the offending file.
Worked example: Fixing inconsistent conventions in a Claude Code monorepo (Scenario 2)
Your team uses Claude Code across a monorepo: packages/web (React functional components with hooks) and packages/api (async/await handlers with a specific error style). Months ago you added the team's conventions to your own ~/.claude/CLAUDE.md, and Claude has followed them ever since, so you assume the whole team is covered.
A new engineer joins and reports that Claude generates code ignoring the conventions: class components in web, inconsistent error handling in api. You run /memory on your machine and see your user-level file loaded. On their machine, that file does not exist, so nothing enforces the standards. Root cause: the conventions live in user scope and were never in the repository.
The fix is a move, not a rewrite. You relocate the standards into committed project memory and, because the single file would be large, you organize it modularly:
# ./CLAUDE.md (repo root, committed)
This is a monorepo. Follow the shared standards below.
@.claude/rules/testing.md
@.claude/rules/api-conventions.md
# ./packages/web/CLAUDE.md (directory-level)
Use functional components with hooks. No class components.
@../../.claude/rules/testing.md
Now .claude/rules/ holds testing.md, api-conventions.md, and deployment.md as focused topic files. The root CLAUDE.md stays short and imports what is universal; each package's CLAUDE.md imports only what its maintainer knows is relevant and adds package-specific rules. After the new engineer pulls the repo, /memory on their machine now lists the project files, and generation is consistent.
The lesson: shared standards must be committed (project scope), large memory should be decomposed with .claude/rules/ plus @import, and /memory is how you prove which files are actually in play.
Exam tips
- ✓Team-shared instructions belong in project-level CLAUDE.md committed to git; ~/.claude/CLAUDE.md is personal and machine-local, so it never reaches teammates or CI.
- ✓The signature diagnostic: a teammate is missing behavior you have. It is in your user-level config, not the repo. Fix by moving it to project CLAUDE.md, not by rewording.
- ✓@import pulls another file's contents into CLAUDE.md; paths can be relative or absolute (~ works), imports nest up to five levels, and @-references inside code fences are literal, not imports.
- ✓Split a bloated CLAUDE.md into focused .claude/rules/ files (testing.md, api-conventions.md, deployment.md) rather than one giant file; this cuts token load and attention dilution while staying team-shared.
- ✓Use /memory to list and edit which memory files are loaded when behavior is inconsistent across sessions; a missing file in that list reveals a scoping bug.
- ✓Memory is plain markdown discovered by location. There is no config.json commands array and no CLAUDE_HEADLESS-style flag for memory; enterprise managed policy is the only tier that cannot be overridden.
Official exam objectives for 3.1
- The CLAUDE.md configuration hierarchy: user-level (~/.claude/CLAUDE.md), project-level (.claude/CLAUDE.md or root CLAUDE.md), and directory-level (subdirectory CLAUDE.md files)
- That user-level settings apply only to that user — instructions in ~/.claude/CLAUDE.md are not shared with teammates via version control
- The @import syntax for referencing external files to keep CLAUDE.md modular (e.g., importing specific standards files relevant to each package)
- .claude/rules/ directory for organizing topic-specific rule files as an alternative to a monolithic CLAUDE.md
- Diagnosing configuration hierarchy issues (e.g., a new team member not receiving instructions because they're in user-level rather than project-level configuration)
- Using @import to selectively include relevant standards files in each package's CLAUDE.md based on maintainer domain knowledge
- Splitting large CLAUDE.md files into focused topic-specific files in .claude/rules/ (e.g., testing.md, api-conventions.md, deployment.md)
- Using the /memory command to verify which memory files are loaded and diagnose inconsistent behavior across sessions
Flashcards from this lesson
Where do you put coding standards so every teammate gets them automatically?
Project-level CLAUDE.md (root ./CLAUDE.md or .claude/CLAUDE.md) committed to version control. Not ~/.claude/CLAUDE.md, which is personal and never shared.
A new hire's Claude ignores conventions that work fine for you. Most likely cause?
The instructions live in your user-level ~/.claude/CLAUDE.md, which is not in git. Move them to project-level CLAUDE.md and commit.
What does @import do in CLAUDE.md, and what are its rules?
It pulls another file's contents into memory. Paths are relative or absolute (~ allowed), imports nest up to five levels, and @-references inside code fences are treated as literal text.
How do you verify which memory files are currently loaded?
Run the /memory command. It lists loaded memory files and lets you edit them, which is how you diagnose inconsistent behavior across sessions.
What is the modular alternative to one monolithic CLAUDE.md?
Split it into focused topic files under .claude/rules/ (e.g., testing.md, api-conventions.md, deployment.md), optionally referenced via @import. These stay version-controlled and team-shared.
When does a subdirectory (directory-level) CLAUDE.md apply?
It is loaded on demand when Claude works with files in that subtree, scoping conventions to a single package or folder without affecting the rest of the repo.
Does ~/.claude/CLAUDE.md sync to teammates through git?
No. It is user-scoped and machine-local. Only files committed in the repository (project and directory CLAUDE.md, .claude/rules/) are shared.