Context and controlGuide 5 of 12
Memory and context
How to organize your project's instructions in CLAUDE.md and scoped rules, so you supply useful context without overloading the session.
Updated 8 min read
// on this page
The two memory systems
Claude Code has two memory mechanisms, complementary to each other, and both load at the start of every session. They aren’t alternatives: they solve different things.
CLAUDE.md files | Auto memory | |
|---|---|---|
| Who writes it | You | Claude |
| What it holds | Instructions and rules | Lessons and preferences it saw you correct |
| Scope | Project, user, or organization | Per repository |
| Used for | Conventions, commands, project architecture | Your preferences and context that can’t be inferred from the code |
CLAUDE.md is the onboarding manual you write. It’s loaded from the current directory and from every directory above it, and the files accumulate instead of overriding each other. Its locations, from broadest to most specific scope:
| Scope | Location |
|---|---|
| Managed policy (organization) | /Library/Application Support/ClaudeCode/CLAUDE.md on macOS |
| User | ~/.claude/CLAUDE.md |
| Project | ./CLAUDE.md or ./.claude/CLAUDE.md |
| Local, uncommitted | ./CLAUDE.local.md (add it to .gitignore) |
Auto memory is the notes Claude writes on its own, out of your corrections. It lives in ~/.claude/projects/<project>/memory/, with a MEMORY.md index and one file per topic. It stores four kinds of note, marked in the frontmatter with the type field: user (your role and how you work), feedback (corrections you gave it), project (decisions and work in progress that can’t be inferred from the code), and reference (where to find information outside the project).
It’s on by default. You turn it on and off with the /memory command, or with autoMemoryEnabled in settings.json. From the MEMORY.md index it loads the first 200 lines or 25 KB, whichever comes first; it reads the per-topic files on demand.
How to write a good CLAUDE.md
Everything you put in CLAUDE.md consumes context-window tokens on every interaction. A bloated file doesn’t just waste budget: it lowers the quality of the answers, because Claude has more instructions competing for its attention and follows them less consistently.
Simple rule: include only what would cause errors if it were missing. Everything else is noise.
Reference size: aim for a maximum of ~200 lines. If it grows past that, it’s a sign you need to split it up with modular rules (.claude/rules/, see below) or with @ imports.
What to include:
- The exact build, test, and lint commands (Claude will run them literally).
- Architecture decisions that affect how the code is written.
- Code conventions specific to the project.
- Required environment variables and services.
- Common traps or patterns Claude should avoid.
- Monorepo structure: which package is responsible for what.
What not to include:
- Things Claude already knows (standard syntax, common APIs).
- Obvious reminders (“write clean code”).
- Long style guides a linter already enforces.
- Complete documentation for external APIs (better to reference it with
@).
Never ask an LLM to do a linter’s job. LLMs are expensive and slow compared to ESLint or Prettier. If the code already follows a style guide, Claude tends to respect the existing patterns through in-context learning, without being told. For what a linter doesn’t cover — or to force the formatting every time, without relying on the model inferring it — use a Hook that runs the formatter automatically (Skills, subagents, and hooks).
How to write the rules:
# ❌ Bad (a suggestion, not verifiable)
- It'd be nice to handle business errors properly
- We prefer controllers not to have business logic
# ✅ Good (imperative, specific, verifiable)
- Business errors are thrown as `AppError({ code, status })`, never
a generic `throw new Error(...)`
- Controllers only parse the request and call the service — business
logic lives only in services/
- Test files sit next to the module they test, with a `.test.ts`
suffix
- API routes go in src/routes/, one file per resource
Use IMPORTANT or YOU MUST sparingly: save them for 2-3 critical rules whose violation causes serious problems. If you mark ten rules as IMPORTANT, Claude stops treating them as exceptional.
- IMPORTANT: Never reprocess or cancel a payment manually from the
code. Refunds always go through the payments service, never with a
direct UPDATE on the table.
- YOU MUST run `npm run lint:fix` before considering a change done.
Modular rules with .claude/rules/
When CLAUDE.md gets too large, split it into topic files inside .claude/rules/ (at the project or global level). Each file can be restricted to certain directories or extensions using glob patterns, so it only loads when it’s relevant to what you’re touching.
Glob pattern syntax
A glob is a template with wildcards that gets matched against a file path: either it matches or it doesn’t. It isn’t a regex — the dot . is literal and there are no quantifiers like + or {3,5}.
| Symbol | What it means | Example |
|---|---|---|
* | Any text within a single path segment (doesn’t cross /) | *.ts → index.ts, not src/index.ts |
** | Any text, crossing directories | src/**/*.ts → any .ts under src, at any depth |
? | Exactly one character | v?.md → v1.md, not v10.md |
[abc] / [a-z] | One character from a set or range | [0-9].txt → 0.txt through 9.txt |
[!abc] | One character not in the set | [!_]*.js → excludes the ones starting with _ |
{a,b} | Alternatives (works like an OR) | *.{js,ts} → app.js or app.ts |
!pattern | Excludes already-included paths — supported depending on the tool, not in the rules’ paths field | !**/*.test.ts |
Examples you’ll use often:
---
paths:
- "src/**/*.{jsx,tsx}" # React components in src
- "db/migrations/[0-9][0-9][0-9][0-9]_*.sql" # numbered migrations
- "**/__tests__/**" # anything inside a __tests__
---
Typical mistakes:
- Confusing
*with**.src/*.tsdoesn’t cover subfolders; for that you needsrc/**/*.ts. **not isolated properly.src**/foodoesn’t work as a globstar; it has to sit alone between slashes:src/**/foo.- Thinking they’re regexes.
app.jsin a glob is exactlyapp.js, literal dot included. - Forgetting hidden files.
.envand.gitignoreusually fall outside generic patterns like*.json; if you want to include them, be explicit with.*or**/.*.
These same globs are used in three places in Claude Code: the paths field of .claude/rules/ rules, the permission rules (Permissions in Claude Code), and a skill’s paths field (Skills, subagents, and hooks) — learning them once covers all three.
Viewing and editing memory
The /memory command lists your CLAUDE.md and CLAUDE.local.md files by scope, lets you open them in your editor, turn auto memory on or off, and open the automatic memory folder. To check what actually loaded in the current session, the command is /context, which shows the files under Memory files.
Two things worth knowing:
AGENTS.mdisn’t read. Claude Code readsCLAUDE.md. If the repo already usesAGENTS.mdfor other agents, the recommended fix is aCLAUDE.mdthat imports it with@AGENTS.mdand adds whatever is Claude-specific below.- In monorepos,
claudeMdExcludeslets you skip other teams’CLAUDE.mdfiles that sit above yours in the directory tree.
Related documentation: official memory and CLAUDE.md reference.