A pattern I keep seeing (and kept doing myself): Claude ignores a rule, so you open CLAUDE.md and rewrite the wording. Stronger verbs, ALL CAPS, a threat or two. Nothing changes — because the file never entered the context window in the first place. You were editing a document nobody was reading.
Claude Code has two slash commands that get conflated here, and they answer different questions:
-
/contextanswers: what actually made it into this session? -
/memoryanswers: what should future sessions start with?
One is an audit. The other is an editor. Mixing them up is how you burn an afternoon polishing prose that was never loaded.
/context: the audit
Run /context mid-session and you get a breakdown of what's occupying the window right now — including a Memory files list showing which CLAUDE.md files (and your auto memory index) actually loaded.
This is the diagnostic to run first, before touching any file. The official docs are explicit about the verification step: after setting up a project CLAUDE.md, "to confirm the file loaded, run /context in a session and check the list under Memory files."
Why this matters: not every CLAUDE.md loads at launch. Files at the project root and above load in full; files in subdirectories load lazily, only when Claude reads something in that directory. A rule sitting in packages/api/CLAUDE.md is invisible until the session touches that subtree. If you've never seen your nested file in the /context list, the problem was never your wording. (I went deeper on load order in Which CLAUDE.md files Claude Code actually loads, and on catching silent load failures in Did Claude Code actually load your rules?.)
/memory: the editor
/memory opens the memory file picker: every CLAUDE.md scope that applies to the current project (user-level ~/.claude/CLAUDE.md, project ./CLAUDE.md or ./.claude/CLAUDE.md, local CLAUDE.local.md), plus the auto memory toggle.
Two things about it that are easy to miss:
- It edits what loads next session, not what's loaded now. Instructions enter context at session start. Editing a memory file mid-session doesn't retroactively inject it.
- The scope you pick matters more than the words you write. A personal preference in the project CLAUDE.md gets pushed to your whole team; a team convention in your user file silently diverges from your coworkers. If you're unsure what belongs where, I wrote up a sorting rule in What actually belongs in CLAUDE.md.
Auto memory, in sixty seconds
The second thing /memory manages is the memory Claude writes — notes it takes on its own about your project: build commands, debugging insights, corrections you've made twice.
The mechanics, from the docs:
-
Location:
~/.claude/projects/<project>/memory/, where the project path is derived from the git repository — so all worktrees of the same repo share one memory directory. It's machine-local; nothing syncs. -
Structure: a
MEMORY.mdindex plus optional topic files (debugging.md,api-conventions.md, …). Only the index loads at startup; topic files are read on demand. -
The load limit is the detail worth knowing: the first 200 lines or 25KB of
MEMORY.md, whichever comes first, load into every session. Everything past that threshold silently doesn't. Claude Code nudges the model to keep the index short and push detail into topic files, and since v2.1.211 the measurement strips YAML frontmatter and HTML comments before counting. -
Toggle: the
/memorypanel writesautoMemoryEnabledinto your user settings; a project can opt out with the same key in its own settings, andCLAUDE_CODE_DISABLE_AUTO_MEMORY=1kills it via environment.autoMemoryDirectoryrelocates the storage if you want it somewhere else.
CLAUDE.md, by contrast, has no load cap — it loads in full regardless of length. Which cuts both ways: nothing gets truncated, and nothing stops you from shipping a 900-line file that degrades adherence for everything in it.
Symptom → command
The mapping I actually use:
| Symptom | First move |
|---|---|
| Rule ignored this session |
/context — is the file even in the Memory files list? |
| Rule ignored every session, file confirmed loaded | Edit for specificity via /memory — shorter and concrete beats emphatic |
| Same correction typed two sessions in a row | Add it to CLAUDE.md via /memory (or let auto memory catch it) |
| Claude "remembers" something wrong or stale | Open the memory directory and prune MEMORY.md — it's a file, not a database |
| Nested rule never seems to apply | Check lazy loading before rewriting — subdirectory files load on file-touch |
The honest caveat
Both mechanisms are context, not enforcement. The docs say it flatly: Claude treats memory "as context, not enforced configuration." A rule can be loaded, verified in /context, perfectly worded — and still lose to a stronger pull in the moment. For anything that must never happen, the answer isn't better prose in either file; it's a PreToolUse hook that blocks the action mechanically. I walked through that setup in Claude Code hooks explained.
/context tells you what's real. /memory changes what's real tomorrow. Hooks are for the things that can't afford to depend on either.
I maintain Rulestack — tested rule packs, skills, and templates for Claude Code, Cursor, and Codex.
Daily notes on AI coding agents on Bluesky: @ai-shop.bsky.social
Top comments (8)
This is the right distinction. I would add one small habit before editing any memory file. Write down the failure you expected the rule to prevent, then check whether that rule is actually in context. Otherwise the memory file becomes a place to store frustration instead of a control surface.
That habit closes the loop — writing the expected failure down first turns 'add a rule' from venting into a testable hypothesis. The pairing I'd add on my side: re-checking /context at the next session start, since that's when loading actually decides whether the fix shipped. 'Control surface vs frustration storage' is a framing that's going to stick with me.
Exactly. The next-session check is the part that keeps memory work honest. I’ve been trying to treat it like a migration, not a note to future me. If the loaded context doesn’t change, the rule didn’t ship.
'Treat it like a migration' is a sharper framing than mine — migrations come with an implicit rollback and a definition of applied, which notes never have. 'If the loaded context doesn't change, the rule didn't ship' — I might steal that as the one-line test. Curious if you fail loudly when a migration doesn't take, or just re-run it?
I noticed the lazy loading detail - rules in subdirectories only load when touched, which explains why my project's api rules were invisible until I added a test file. The 200-line MEMORY.md limit is also key: it forces me to split debugging notes into topic files instead of bloating the index. For critical rules, I'd add a PreToolUse hook to override context entirely - because no amount of wording can prevent a bad action.
The subdirectory example is the best kind of evidence — the rule was 'there' the whole time, it just never had a trigger until a file in that path got touched. And agreed on PreToolUse for the rules that must hold: wording competes for attention in context, a hook doesn't. You've got me re-sorting which of my 'critical' rules are actually invariants that belong in a hook.
I like the distinction between checking what loaded and changing what loads next. It turns context from a vague feeling into an inspectable runtime state. The next useful layer is probably a small diff: expected context versus actual context for this run.
The expected-vs-actual diff is the piece I keep circling too. What stopped me: 'expected' has no canonical home — it lives half in settings, half in people's heads. Your framing of context as inspectable runtime state might be the right wedge for making that explicit. Did you have a shape in mind for where 'expected' gets declared?