Module 3 — CLAUDE.md, rules and memory: teach the project to Claude
Module 2 showed why Claude re-reads CLAUDE.md at every /compact. This module draws the consequences: what to write in it, what to move out into scoped rules, what to leave to the automatic memory that Claude fills on its own. On Kiosque, we replace the CLAUDE.md generated by /init with a durable file that will survive three refactors.
Two complementary mechanisms
Every session starts on an empty context. Two mechanisms fill it: CLAUDE.md files you write (instructions, rules, loaded on every session — project, user, organization) and automatic memory Claude writes (your role, preferences, what you correct often, facts Claude cannot infer from the code).
Both are context, not executed configuration. An instruction is still a directive a model may ignore if it is vague or contradictory. To block something deterministically — refuse a write to .env, force a lint — you need a PreToolUse hook (module 9). The triptych is: CLAUDE.md for what Claude must know, skills for what it must know how to do on demand, hooks for what must happen no matter what.
Memory-file hierarchy
CLAUDE.md files can live at several levels. Loading order goes from the broadest to the most specific — each level adds up, none replaces another.
| Scope | Location | Usage |
|---|---|---|
| Managed policy | macOS /Library/Application Support/ClaudeCode/CLAUDE.md, Linux/WSL /etc/claude-code/CLAUDE.md, Windows C:\Program Files\ClaudeCode\CLAUDE.md | Instructions managed by IT or DevOps, security standards, legal obligations |
| User | ~/.claude/CLAUDE.md | Personal preferences applicable to every project |
| Project (shared) | ./CLAUDE.md or ./.claude/CLAUDE.md | Team conventions, build commands, architectural decisions. Committed |
| Local (personal) | ./CLAUDE.local.md | Your sandbox URLs, test data. Added to .gitignore |
Claude Code loads CLAUDE.md and CLAUDE.local.md from your current directory and every folder above it, top-down. Files in subfolders only load on demand — when Claude reads a file inside that subfolder. This behavior is precious in a monorepo: apps/back/CLAUDE.md does not enter the context until you touch the backend.
A CLAUDE.md above 4 MiB is ignored; a file over 200 lines or 25 KB consumes a lot of context and drops adherence. The default usage is to stay under 200 lines.
Writing effective instructions
Verbal instructions fail: "format correctly", "test your code". Verifiable instructions succeed: "use 2-space indentation", "run make test before committing", "API handlers live in app/api/handlers/". Add to CLAUDE.md every time Claude makes the same mistake twice or a code review catches something it should have known. A short sentence, one fact per line, beats a dense paragraph.
What not to put in it: the folder tree, the list of dependencies, architecture (Claude infers it); multi-step procedures (that is a skill, module 6); anything specific to a subfolder (that is a scoped rule); tokens or secrets (the file is committed).
.claude/rules/: split by topic, scope by path
The .claude/rules/ folder lets you break CLAUDE.md into topic files. Every .md under this folder loads recursively, with the priority of .claude/CLAUDE.md if it has no frontmatter. One file per topic (api.md, front.md, security.md) stays easier to maintain than a single fat CLAUDE.md.
The value comes from the paths: frontmatter: a scoped rule only loads its body when Claude reads a matching file.
---
paths:
- "app/**/*.py"
- "tests/**/*.py"
---
# API rules
- Every FastAPI route validates its inputs via Pydantic.
- Error responses follow the `{code, message, details}` format.
- SQLAlchemy migrations are generated with `alembic`.
- No direct session access outside dependency injection.
Patterns follow the usual glob syntax: **/*.ts, src/api/**/*.ts, src/**/*.{ts,tsx} with brace expansion (budget of 1,000 expanded patterns and 4 MiB per rule). A pattern that is not parseable as a bracket expression no longer blocks loading since v2.1.207: it matches nothing, and the rule keeps working on the others.
Rules apply when Claude reads a matching file, not on every tool call. Since v2.1.198, matching also works via a symlinked path.
@path imports
A CLAUDE.md can import other files with the @path syntax (relative to the importing file or absolute). Imports are expanded at startup, with a maximum depth of four.
See @README for the overview and @package.json for the scripts.
## Detailed conventions
- Python style: @docs/python-conventions.md
- Front-end style: @docs/front-conventions.md
Imports in a project-scope file whose path resolves outside the working directory (for example @~/notes.md) are sensitive: the first time, Claude Code opens an approval dialog; a refusal silently disables them. User-scope memory files load their imports without a dialog. To share the same rules across projects, a symlink does the trick: ln -s ~/shared-claude-rules .claude/rules/shared.
AGENTS.md and compatibility
Claude Code reads CLAUDE.md, not AGENTS.md. Two options if your repo already uses AGENTS.md: a CLAUDE.md that imports it (@AGENTS.md), or a symlink ln -s AGENTS.md CLAUDE.md. /init additionally reads .cursor/rules/, .cursorrules, .github/copilot-instructions.md. With CLAUDE_CODE_NEW_INIT=1, it also adds AGENTS.md, .devin/rules/, .windsurf/rules/, .clinerules. The /import [codex|gemini] command (v2.1.213+) brings in another agent's configuration in one pass.
Automatic memory
Automatic memory is enabled by default. Every time Claude learns something durable, it writes it itself under ~/.claude/projects/<project>/memory/. Four kinds of notes marked by a type field: user (your role, preferences), feedback (corrections given to Claude, approaches validated), project (decisions, deadlines, facts Claude cannot infer from the code), reference (where to find information outside the project). Claude does not write every session; it decides on the fly whether a fact is worth keeping and avoids what the code already shows.
The folder contains an index MEMORY.md — the only thing loaded on every session (200 lines or 25 KB) — and one file per topic (user_role.md, feedback_testing.md) read on demand. Since v2.1.214, each note carries a modified field in ISO 8601 when it is rewritten.
To disable: "autoMemoryEnabled": false in the project settings.json, or globally CLAUDE_CODE_DISABLE_AUTO_MEMORY=1. The autoMemoryDirectory key changes the location (absolute path or ~/...). Main-session memory is not loaded in subagents — except a fork, which inherits the parent conversation. A subagent can have its own memory via the memory field of its frontmatter (module 10).
/init, /memory, /doctor
Three commands cover the full life cycle:
/initgenerates a firstCLAUDE.mdby analyzing the repo. WithCLAUDE_CODE_NEW_INIT=1, the interactive variant also proposes skills, hooks and personal memory files, and reads any existingAGENTS.mdor.cursor/rules/configuration. It is a draft: rework before committing./memorylists yourCLAUDE.md,CLAUDE.local.mdand memory files at every scope, including those that do not exist yet. Select an item to open it in your editor; if it does not exist,/memorycreates it first. The command also exposes the automatic-memory toggle and a direct link to the memory folder./doctor(alias/checkup) runs a full diagnostic and proposes fixes: duplicate installs,PATH, unreadable settings, unused skills, dormant MCP servers, oversizedCLAUDE.md. Since v2.1.206, it slims down a committedCLAUDE.md: it removes what Claude can infer from the code (folder tree, dependencies) and keeps the pitfalls, the rationale, and the conventions that diverge from defaults. It migrates the always-unused parts into skills or nestedCLAUDE.mdfiles that load on demand.
What survives /compact
After /compact, the repo CLAUDE.md and rules without paths: are re-injected from disk. An instruction added inside the conversation disappears; an addition to CLAUDE.md survives every compaction. The right reflex when you correct Claude twice: add the rule. /memory does it in three keystrokes.
Team management
CLAUDE.md is committed; CLAUDE.local.md is not. Encode shared conventions in the first, personal preferences in the second. An organization can push a managed CLAUDE.md or a claudeMd in managed-settings.json that user, project and local settings cannot override — useful for compliance reminders, not for code conventions (which live in the repo).
In a monorepo, the claudeMdExcludes key (in a settings.json at any scope except managed policy) skips other teams' CLAUDE.md files that linger in parent folders; patterns match on the absolute path. A managed-policy CLAUDE.md can never be excluded.
Running example: a real CLAUDE.md for Kiosque
/init in module 1 produced a chatty file. We rewrite it by hand so it fits in roughly forty useful lines:
# CLAUDE.md — Kiosque
Order-taking app for food trucks: FastAPI API in `app/`, React
front-end in `web/`, SQLite via SQLAlchemy.
## Commands
- `make dev` : starts the API on `:8000` and the front on `:5173`.
- `make test` : pytest; never commit if red.
- `make lint` : `ruff format` then `ruff check --fix`.
- `mypy app/` : before every PR touching the API.
## Conventions
- **French domain entities**: `commande`, `paiement`, `menu`. The
English code is legacy to convert, not to imitate.
- Routes in `app/routers/`, models in `app/models.py`, pure services
in `app/services/`.
- Pydantic schemas as `In` / `Out` (`CommandeIn`, `CommandeOut`).
- `httpx` for outbound calls, never `requests`.
## Pitfalls
- `test_paiements_delai` is flaky — no conclusion on an isolated run.
- `.env` **never** read or written by Claude.
- SQLAlchemy migrations via Alembic; no direct DDL.
## Compact instructions
- Keep architectural decisions and conventions.
- Drop read code snippets and one-off explorations.
Alongside it, .claude/rules/api.md scoped to app/**/*.py and tests/**/*.py (Pydantic, error format {code, message, details}, Alembic migrations) and .claude/rules/front.md scoped to web/**/*.{ts,tsx} (functional components, TanStack Query, Tailwind). We add .env to .gitignore. Module 9 will add a PreToolUse hook refusing writes to .env: the belt-and-suspenders that makes the rule non-negotiable.
Common mistake: "why is Claude not following my rule?"
Three causes keep coming up: the rule is not loaded — /context lists the Memory files; a missing file has no effect, check the path and, for a scoped rule, that Claude actually read a matching file; the rule is vague — "format properly" is worthless against "2-space indentation"; the rule contradicts another one, Claude decides arbitrarily (/doctor sometimes detects the duplication). One last lever: the InstructionsLoaded hook (module 9) traces exactly which instruction files load, when, and why.
Summary
- Two mechanisms:
CLAUDE.mdyou write, automatic memory Claude fills. Both are just context. - Hierarchy: managed policy → user → project → local; levels stack.
.claude/rules/*.mdwithpaths:avoids bloating the mainCLAUDE.md.@pathimports expanded four levels deep; symlinks to share rules across projects.AGENTS.md: not read by default; use@AGENTS.mdor a symlink, or run/import.- Automatic memory: four types (
user,feedback,project,reference) under~/.claude/projects/<project>/memory/. /initproduces a draft,/memoryedits,/doctorslims down. ACLAUDE.mdunder 200 lines goes the distance.
Next module: Built-in slash commands (1/2): session, context, configuration and model — the exhaustive reference of the eight families with every alias and every argument.