Where does this instruction belong?
- True in every session
CLAUDE.mdLoaded at every session start - Only for some files
.claude/rules/Path-scoped, loads on match - A whole procedureSkillLoads when invoked or relevant
- Must never happenHookCode, not context
The core components
Five mechanisms extend a Claude Code session, and they differ in one dimension above all: when their content enters the context window.
| Component | Lives in | When it loads |
|---|---|---|
| Rules and instructions | CLAUDE.md, ./.claude/CLAUDE.md, .claude/rules/*.md | Every session; path-scoped rules load when Claude touches matching files |
| Skills | .claude/skills/ and ~/.claude/skills/ | Descriptions at start; the full content only when invoked or judged relevant |
| Commands | .claude/commands/ and ~/.claude/commands/ | When you type /name |
| Agents (subagents) | .claude/agents/ and ~/.claude/agents/ | When Claude delegates, or you name one |
| Auto memory | ~/.claude/projects/<project>/memory/ | The MEMORY.md index every session; topic files on demand |
The practical rule follows from the right-hand column. Anything that must be true all the time goes in a memory or rules file and costs context on every request. Anything that matters occasionally goes in a skill, so it costs almost nothing until it is needed. Anything that must be obeyed rather than considered goes in a hook, because instruction files are context, not enforced configuration.
The CLAUDE.md hierarchy
Claude Code loads CLAUDE.md and CLAUDE.local.md from the working directory and every directory above it, concatenating them rather than letting one override another. Content is ordered from the filesystem root down to where you launched, so the most specific file is read last. Files in subdirectories below the working directory are not loaded at launch — they load when Claude reads files in those directories.
Memory files, broadest first
loaded in this order, top to bottom
- Managed policyorganisation-wide, deployed by IT
- User
~/.claude/CLAUDE.md, all your projects - Project
./CLAUDE.mdor./.claude/CLAUDE.md - Local
./CLAUDE.local.md, gitignored - Subdirectoryloads when Claude reads those files
A CLAUDE.md can pull in other files with @path/to/file, expanded at launch, recursively, to a maximum depth of four hops. Wrap a path in backticks to mention it without importing it. The guidance on size is blunt: aim under 200 lines, because longer files consume context and reduce adherence — split by topic into .claude/rules/, where a paths frontmatter field scopes a rule to matching files so it loads only when relevant.
A CLAUDE.md that works
Vague
# Project notes
Format code properly and
keep files organised.
Test your changes before
you commit anything.
Follow our conventions.Verifiable
# Payments API
- Use 2-space indentation
- Run `npm test` before
committing
- Handlers live in
`src/api/handlers/`
- Never edit
`db/migrations/` by handSlash commands, built-in and custom
A slash command is recognised only at the start of a message, and whatever follows the name becomes its arguments. The built-ins worth knowing by name: /init to bootstrap a project, /clear to start a fresh conversation, /compact to summarise the current one, /context to see what is occupying the window, /memory to view and edit memory files, /resume to return to an earlier conversation, /agents to manage subagents, /permissions and /config for rules and settings, /mcp for server connections, /model and /status.
Custom commands are markdown files: .claude/commands/ for ones the team shares through version control, ~/.claude/commands/ for your own across every project. The body is the prompt; YAML frontmatter can set description, argument-hint, allowed-tools and model. Inside the body, $ARGUMENTS is everything typed after the name, and $1, $2 pick out individual arguments.
---
description: Security audit for a package
argument-hint: "[scope]"
allowed-tools: bash, read
model: opus
---
Run a security audit on $ARGUMENTS. Check for injection,
hardcoded secrets and insecure dependencies. Report each
finding as file:line followed by one line of explanation.Sessions, headless mode and streaming
A session is the conversation transcript, written to disk automatically. /resume returns to one interactively. From a script, --continue picks up the most recent conversation in the directory and --resume <session-id> returns to a specific one — capture the id from the JSON output when you start it.
Headless mode is the same tool without the terminal interface: claude -p "…". It reads standard input, so you can pipe a diff or a log into it, and it exits non-zero when a run fails so a pipeline can branch on the status. Three output formats: text (the default), json (the result plus session id, usage and cost) and stream-json (newline-delimited events as they happen).
# Pipe a diff in, get plain text out
git diff main | claude -p "list any typos as file:line" --allowedTools "Read"
# Structured output, then reuse the session id
session=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Now focus on the database queries" --resume "$session"
# Event-by-event streaming for a live UI
claude -p "Explain recursion" --output-format stream-json --verboseA headless run in CI
- Pipe inputdiff, log or prompt on stdin
claude -pwith--allowedTools- Read output
text,jsonorstream-json - Branch on exitnon-zero fails the job
settings.json and who wins
Settings files hold configuration rather than instructions: permission allow, ask and deny rules, hooks, environment variables, the default model, plugins. Four files, plus managed settings an organisation can deploy.
| Scope | File | Affects |
|---|---|---|
| Managed | managed-settings.json and other managed sources | Everyone the organisation deploys it to; you cannot override it |
| Command line | claude --settings <file-or-json> | This session only |
| Project local | .claude/settings.local.json | You, in this project; kept out of git |
| Shared project | .claude/settings.json | Everyone who clones the repository |
| User | ~/.claude/settings.json | You, in every project on this machine |
That table is also the precedence order, highest first: managed, then command line, then project local, then shared project, then user. A key set higher wins. There is one important exception to the mental model — list keys such as permissions.allow merge across files rather than overriding, so each file can add entries without erasing another's.
Traps the wrong answers are built from
| Tempting but wrong | Do this instead |
|---|---|
Putting a long procedure in CLAUDE.md | Move it to a skill so it loads only when that kind of work comes up. |
Relying on CLAUDE.md to prevent a dangerous action | Memory files are context, not enforcement — use a PreToolUse hook. |
Expecting a project CLAUDE.md to override a user one | Memory files concatenate; it is settings files that override. |
Running claude -p in CI with broad tool access | Pre-approve narrow rules such as Bash(git diff *), and consider --bare for reproducibility. |
Treating /init output as the finished configuration | Add the facts the model cannot discover, then keep the file short. |
You should now be able to
- Place an instruction correctly across
CLAUDE.md,.claude/rules/, skills, commands and hooks. - State the
CLAUDE.mdload order and explain that files concatenate rather than override. - Write a custom slash command with frontmatter and arguments.
- Run Claude Code headlessly with the right output format and pre-approved tools.
- Resolve which settings file supplies a value, and recognise where lists merge instead.