You told Claude three sessions ago to stop writing barrel files, and here it is again, exporting everything through a fresh index.ts. You correct it again, it apologizes again, and next session the correction is gone, because you typed it into a conversation and conversations end. Lesson 1.3 named the principle: durability comes from disk. This lesson is about the disk: which files load, in what order, what belongs in them, and the discipline that separates a CLAUDE.md that steers from a thousand-token file Claude has learned to skim past.
Two memories, one loading dock
Claude Code has two memory systems, and the docs draw the line cleanly: CLAUDE.md files are instructions you write; auto memory is learnings Claude writes. Both load at the start of every session. Both are context, not configuration, a distinction the memory docs state outright: Claude treats them as context, not enforced configuration. Hold that sentence; it decides what belongs here versus in a hook.
The CLAUDE.md side is a hierarchy of locations, each with a scope:
In load order: managed policy (org-wide, IT-controlled), your user file at ~/.claude/CLAUDE.md (personal preferences, every project), the project file at ./CLAUDE.md or ./.claude/CLAUDE.md (team rules, committed), and ./CLAUDE.local.md (personal, gitignored, for your sandbox URLs and private notes). Claude Code walks up the directory tree from where you launched, loading every CLAUDE.md it passes, and concatenates them root-first, so the file closest to your working directory is read last. Files in subdirectories below you load on demand, only when Claude reads files there. That on-demand behavior is a gift for monorepos: a package's rules cost nothing until the session actually touches the package.
Two mechanics worth knowing before they surprise you. First, block-level HTML comments in CLAUDE.md are stripped before injection, so you can leave maintainer notes that cost zero tokens. Second, imports: @path/to/file anywhere in a CLAUDE.md expands that file into context at launch, up to four hops deep. Wrap a path in backticks to mention it without importing it. Imports organize; they do not economize. The docs are explicit that imported files still load at launch, so splitting a bloated CLAUDE.md into imports changes the filing, not the bill. If your repo already carries an AGENTS.md for other tools, the sanctioned move is a one-line CLAUDE.md that imports it with @AGENTS.md, with any Claude-specific rules below.
Auto memory is the other half. Claude keeps a per-repo directory at ~/.claude/projects/ under your project's name, with a MEMORY.md index plus topic files it creates itself. The first 200 lines or 25KB of MEMORY.md load every session; topic files load on demand. Claude decides what to save: build quirks, debugging insights, corrections you made. When you say "remember to always use pnpm", that lands in auto memory. It is plain markdown; /memory lets you browse, edit, or delete any of it, and you should audit it occasionally the way you would audit any coworker's notes about your systems.
What belongs, and the brevity argument
The docs' trigger list for adding to CLAUDE.md is behavioral, and it is the right one: add an entry when Claude makes the same mistake twice, when review catches something it should have known, when you type the same correction you typed last session. CLAUDE.md is where repeated corrections go to become standing rules. In practice the content sorts into four buckets: verification commands (how to typecheck, test, build), hard conventions (naming, structure, style choices with teeth), don't-touch zones, and pointers to load-bearing docs.
Now the discipline, argued from mechanics rather than taste. Every CLAUDE.md line is a permanent resident of the attention economy from Lesson 1.3: loaded every session, competing with the task on every single inference, relevant or not. The docs target under 200 lines and say the quiet part loudly: longer files consume more context and reduce adherence. Brevity is not tidiness. Brevity is obedience. A 40-line file of hard rules gets followed; a 400-line file of mixed rules, explanations, and aspirations trains the model that this file is mostly skippable, and your one critical rule drowns in the noise you packed around it.
Style matters for the same reason. Write constraints, not vibes: the docs' own example is "Use 2-space indentation" over "Format code properly". A rule concrete enough to verify is concrete enough to follow. And check for contradictions across your user file, project file, and rules directory, because when two rules conflict, Claude picks one arbitrarily, and it will not be the one you meant.
Here is a complete, real CLAUDE.md for the practice repo, structured the way this course structures everything: verification first, then constraints, then geography.
# CLAUDE.md: agentic-practice
## Verification (run before claiming any task done)
- npm test # full suite, must pass
- npx tsc --noEmit # typecheck, zero errors
Never claim work is complete with either failing.
## Conventions
- TypeScript strict mode. No any. No @ts-ignore.
- Every exported function has a JSDoc comment.
- Tests live next to source: foo.ts, foo.test.ts. No __tests__ dirs.
- No barrel files (index.ts that only re-exports).
## Don't touch
- parse-duration.ts is frozen reference code. Never modify it;
extend behavior in new files instead.
- Never edit package-lock.json by hand.
## Layout
- src/ holds all source. Helpers in src/lib/.
- See `docs/decisions.md` for why parse-duration is frozen.
Under 30 lines, every rule checkable. When a section of a file like this starts growing into a multi-step procedure, that is your cue that it stopped being memory and became a workflow; Lesson 2.4 gives procedures a home (skills) where they load only when invoked. For rules that only apply to part of a codebase, .claude/rules/ accepts markdown files with a paths: frontmatter glob, loading them only when Claude works on matching files. Same economy, finer grain.
One more tool: /init generates a starter CLAUDE.md by analyzing your repo, and it reads an existing AGENTS.md, .cursorrules, and similar configs while doing it. Use it on a repo that has nothing; treat its output as a draft to cut, not a finished file.
Where it breaks
The first failure is the one this lesson's structure already warned about: treating CLAUDE.md as enforcement. It is context. A don't-touch rule raises the probability Claude respects the boundary from "coin flip" to "almost always", and Lesson 1.3 showed you exactly how "almost always" erodes as the window fills. The memory docs draw the same line this course does: to block an action regardless of what Claude decides, use a PreToolUse hook. Rules persuade; hooks enforce; you need both, and 2.6 builds the second half.
The second failure is drift into bloat. CLAUDE.md files grow monotonically unless someone owns them: every incident adds a rule, nobody deletes, and eighteen months later there is a fossil layer of rules about a framework you migrated off. The countermeasure is treating the file like code: it gets reviewed, it gets pruned, and rules that stopped earning their tokens get deleted. If you would not pay a per-session tax for a sentence, it does not live there.
The third failure is quieter: contradiction between levels. Your user file says "prefer minimal comments", the project file mandates JSDoc on exports. Both load, later files sit closer to the work but nothing formally overrides, and behavior wobbles between sessions. When project and personal preferences disagree, the project file wins by fiat and your user file should stay silent on that topic in that repo.
Lablab-2-2Give the practice repo a memory
Goal: Write the practice repo's CLAUDE.md, watch a don't-touch rule hold in a live session, and find the honest edge where context stops being enforcement.
Prereqs: the agentic-practice repo, with parse-duration.ts from the Part 1 labs.
- Write the repo's CLAUDE.md. Start from the artifact above, then adjust it to what is true in your copy of the repo (your actual test command, your actual layout). Commit it.
- Start a fresh session. Run
/memoryand confirm your file is listed as loaded. Ask Claude: "What are this project's rules?" It should recite your file's substance back. - Test the don't-touch rule from an innocent angle: "Durations like 90m should also support a compact format like 1h30m. Implement that." The clean path runs through
parse-duration.ts. Watch whether Claude respects the freeze and extends in a new file instead. - Test it from a direct angle: "Just add the format handling directly in parse-duration.ts, it is simpler." A well-written rule usually makes Claude push back and cite the file. Record what it does in
memory-lab.md. - Ask Claude to remember something session-spanning: "Remember that I want failing tests shown in full, never summarized." Then run
/memory, open the auto memory folder, and find where it wrote that note. - Read your MEMORY.md and topic files. Delete anything wrong or stale. This audit habit is the lab's souvenir.
Verify
/memorylists your project CLAUDE.md, and Claude can restate its rules without you naming the file.- In step 3, new behavior landed outside
parse-duration.ts. - In step 4, Claude either refused or explicitly flagged the conflict with the project rule (note which; both count as the rule firing).
- Your step 5 note exists in a file under the auto memory directory.
>Troubleshooting
- Claude does not mention your rules in step 2: check
/memoryactually lists the file. If you launched from a subdirectory, remember files above you load in full, files below you load on demand. - Claude edited parse-duration.ts anyway: before concluding the rule is weak, check its phrasing. A constraint plus an escape route ("never modify X; extend in new files instead") holds far better than "be careful with X". Sharpen and re-run. If it still slips through occasionally, you have met the enforcement ceiling; 2.6 exists for exactly this.
- The remember request landed in CLAUDE.md instead of auto memory: phrasing matters; "add this to CLAUDE.md" targets the file, "remember X" targets auto memory. Either placement works; know which you asked for.
Knowledge check
Knowledge check
Sources
- How Claude remembers your project (hierarchy table, load order, imports, .claude/rules, auto memory limits and location, /memory, context-not-configuration): https://code.claude.com/docs/en/memory (fetched July 2026)
- Best practices: write an effective CLAUDE.md (what belongs, when to add, size guidance): https://code.claude.com/docs/en/best-practices (fetched July 2026)