Where to Put Instructions in Claude Code: A Decision Guide
Where to put instructions in Claude Code: CLAUDE.md, rules, skills, custom commands, hooks or auto memory. A decision table built on a real repo.
By Matthews WongReviewed on Checked against Claude Code v2.1.301
Key takeaway
Claude Code gives you several homes for a reusable instruction, and the right one depends on when Claude must see it and whether it is advice or a guarantee. Always-true facts go in CLAUDE.md, occasional procedures in a skill, must-happen rules in a hook, and what Claude learns as you work in auto memory.
You will be able to
- Sort any instruction into CLAUDE.md, a skill, a hook or auto memory with a few questions.
- Explain how custom commands and skills relate today, and which wins a name clash.
- Tell what is shared through git and what stays on your machine.
Step through the diagram
Press Play, or step with the arrows. Every step is written out below the diagram.
One instruction, four possible homes
An instruction that is always true goes to CLAUDE.md, a procedure needed sometimes to a skill, a rule that must hold to a hook, and what Claude learns itself to auto memory.
Reviewed on 17 October 2026 · Claude Code v2.1.301
Keys: ← → step · Home / End · K play or pause
One reusable instruction, four homes. Where it goes decides when Claude sees it, and whether it is only advice or something that always runs.
A fact true in every session, such as a build command or a convention, belongs in CLAUDE.md. It loads at session start, so keep it short.
Predict the next step A long release checklist matters only when you release. Where should it live? (In CLAUDE.md · In a skill · In a hook)Claude sees a skill's description each session; the full text loads when you type /name or Claude matches the task. Command files work the same way.
CLAUDE.md and skills are requests Claude may weigh. A hook runs on its event whatever Claude decides, and adds no context unless it returns output.
Predict the next step You correct Claude's test style twice and edit no file. Which home can still pick that up? (CLAUDE.md, by itself · Auto memory · A hook, by itself)Auto memory is Claude's own notebook, saved per repository on your machine. The first 200 lines or 25KB of its index load each session.
Always true: CLAUDE.md. Sometimes needed: a skill. Must happen: a hook. Learned while working: auto memory. Team knowledge goes in a committed file.
How do you choose where a Claude Code instruction belongs?
Ask three questions in order. Does Claude need it in every session? Then it is context, and CLAUDE.md is the home: build commands, conventions, never-do-X rules. Does Claude need it only sometimes, for one kind of task? Then it is a skill, because a skill's description loads each session but its full content loads only when used. Must it happen every single time, with no judgement involved? Then it is a hook, which runs on its event whatever Claude decides.
Read more (2)Show less
The docs give the same triggers from the other direction. If Claude gets a convention or command wrong twice, add it to CLAUDE.md. If you paste the same playbook into chat for the third time, make it a skill. If you want something to happen every time without asking, write a hook. And the docs state the limit plainly: CLAUDE.md is context, not enforced configuration, so for a rule that must hold, use a hook instead of a prompt instruction.
This repo shows the split. Its CLAUDE.md carries the hard rules every session needs, such as keeping the two message files on the same key tree. The long how-to for writing a post lives in a skill that loads only for blog work. The one thing that must run after every edit, the figure review, is a hook. And the rule that generated sources must not be stale is enforced by the build, which fails, rather than by a sentence anyone could skip.
Slash commands, custom commands and skills: what is the difference now?
Custom commands have been merged into skills. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and work the same way, and existing command files keep working. Skills add a folder for supporting files, frontmatter that controls who invokes them, and the ability for Claude to load them automatically when relevant. The docs recommend a skill for new work. If a command file and a skill share a name, the skill wins.
Read more (2)Show less
Two frontmatter fields decide who can call a skill. With disable-model-invocation: true, only you can run it with /name, and its description stays out of context until you do; use that for workflows with side effects. With user-invocable: false, only Claude can invoke it, and it disappears from the / menu. By default, both of you can. Built-in commands such as /memory and /status are a different thing: they ship with Claude Code, not as files you write.
So the practical choice is rarely command versus skill any more. It is skill versus CLAUDE.md. A skill's description is always in context, so write it so Claude can tell when to use it. This repo never had a .claude/commands/ folder; its procedures went straight into skills.
Where does auto memory fit next to CLAUDE.md?
They are two complementary memory systems, both loaded at the start of a conversation, and both treated as context rather than enforcement. You write CLAUDE.md, and it holds instructions and rules. Claude writes auto memory, and it holds learnings: your role and preferences, corrections you gave, project decisions it cannot derive from the code, and pointers to outside systems. Claude skips what it can read from the codebase and what your CLAUDE.md files already say.
Read more (2)Show less
Auto memory lives in a folder per project under ~/.claude/projects, with a MEMORY.md index and one file per topic. It is machine-local: it is not committed and not shared across machines. Only the first 200 lines or 25KB of MEMORY.md load at the start; topic files are read on demand. Run /memory to browse and open the files and to toggle auto memory, which is on by default in local sessions. You can also edit or delete any note; they are plain markdown.
That makes the sharing rule simple. Knowledge your whole team needs must live in a file you commit: CLAUDE.md, a skill, or a plain note in the repo. This repo's CLAUDE.md points at a dated review file under .dev/review for exactly that reason, so any contributor and any machine sees the same list. Auto memory is for what Claude learns about you and your working style, not for the team's shared record.
The real config behind this lesson
Excerpts from the repository that builds and deploys this website, quoted as they are.
1. **`messages/en.json` and `messages/id.json` must have the exact same key tree.** Missing key in either file → runtime error.
2. **No `{`, `}`, or `<` in blog `content.*` JSON values.** The merge script rejects them. Put markup in JSX; put ICU interpolation only in non-blog UI strings.
3. **Every slug in `BLOG_POSTS_STATIC` must have an entry in `BLOG_META` (and vice versa).** `assertBlogParity()` fails the build otherwise.Always-true rules: they apply to every task in the repo, so they sit in CLAUDE.md, which loads in full each session. They are requests, though. Rule 3 is also enforced, because assertBlogParity() runs in the build and fails it; the sentence tells Claude, the build guarantees it.
---
name: writing-blog-content
description: House standard for writing a bilingual blog post on this site — voice, section skeleton, callout and code-block conventions, the SEO limits enforced by the validators (title 63 chars, description 140-155, 12-15 keywords ending "Matthews Wong"), citation discipline, Indonesian translation rules, and the anti-patterns that make agent-written posts read as filler. Use when drafting, editing or reviewing any blog post, article, excerpt, key takeaway, FAQ, meta description or keyword set for this repository.
---Sometimes-needed knowledge: a skill. Only the description (and name) sits in context every session, and it ends with a trigger, Use when drafting, editing or reviewing any blog post. The long standard under the frontmatter loads when a blog task matches. No tools are listed, so it is read as knowledge, not run as a script.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PROJECT_DIR:-.}/scripts/review-blog-figures.mjs\" --hook 2>/dev/null || true",
"timeout": 30,
"statusMessage": "Checking whether the figures fit"
}
]
}
]
}
}Must-happen behavior: a hook. After every Write or Edit, the figure review runs whether or not Claude remembers. This one only advises, but the trigger is guaranteed, and it costs no context unless the script returns output.
`HubBacklink` (in the blog `[slug]` layout) links an article back to every hub that lists
it. `.dev/review/indonesia-posts-accuracy-2026-10-12.md` tracks which posts still disagree
with current sources.Shared memory the repo keeps itself: a note in git, referenced from CLAUDE.md. A fact like which posts still disagree with current sources changes over time and belongs to everyone, so it is committed rather than left to one machine's auto memory.
Mistakes that cost real time
A must-never rule left only in CLAUDE.md
An instruction like never edit this file in CLAUDE.md or a skill is a request, not a guarantee. If breaking it is costly, enforce it with a PreToolUse hook or a failing build check, and keep the sentence only to explain why.
A CLAUDE.md that keeps growing
The docs target under 200 lines per CLAUDE.md, because longer files cost context and reduce adherence. This repo's own CLAUDE.md is over 600 lines, so treat it as a warning, not a model: its field guides for single sections are candidates to move into skills or path-scoped rules. Imports help organize a file but do not cut its context cost.
A vague skill description
Claude matches your task against skill descriptions. If they are vague or overlap, it may load the wrong skill or miss the right one. Name the files, commands and phrases a request will contain, or invoke the skill yourself with /name.
Team knowledge stored only in auto memory
Auto memory is machine-local. A teammate never sees it, a second laptop has its own, and everything past the first 200 lines or 25KB of MEMORY.md is not loaded at session start. If a fact must reach other people or other machines, put it in a committed file.
| Home | When Claude sees it | Who writes it | Shared via git? | Enforced? |
|---|---|---|---|---|
| CLAUDE.md | Every session, in full | You | Yes | No, it is context |
| Rules in .claude/rules | Every session, or when matching files open | You | Yes | No, it is context |
| Skill or command file | Description always; full text when used | You | Yes, if committed | No, Claude interprets it |
| Hook | On its event, outside the chat | You | Yes, in a shared settings file | Yes, the trigger always fires |
| Auto memory | First 200 lines or 25KB of the index | Claude | No, machine-local | No, it is context |
Do it on your own machine
You need Claude Code in a scratch git repository. You will inspect what is loaded, create one skill, and watch it beat a command file with the same name.
Start Claude Code and run /memory. It lets you browse and open memory files and holds the auto memory toggle. Note which files are in your repo and which are under your home folder.
claude > /memoryCreate a manual-only skill. disable-model-invocation keeps it out of context until you type its name, and $ARGUMENTS receives what you type after it.
mkdir -p .claude/skills/release-notes cat > .claude/skills/release-notes/SKILL.md <<'EOF' --- name: release-notes description: Draft release notes from recent commits disable-model-invocation: true --- Summarize the commits since $ARGUMENTS as release notes, grouped by theme. EOFCreate a command file with the same name and different text. Then restart Claude Code and run /release-notes v1.0. The skill's text should be the one that runs, because a skill beats a command file.
mkdir -p .claude/commands echo 'List the commits since $ARGUMENTS as a plain bullet list.' > .claude/commands/release-notes.md claude > /release-notes v1.0Sort five instructions of your own with the three questions: always needed, sometimes needed, must happen. Write each one's home next to it, and commit only the ones that are team knowledge.
Three questions before you move on
Pick an answer to see why it is right or wrong. Nothing is saved or graded, so guess freely.
Answer in your head, then check
1.Which three questions sort an instruction into its home?Show the answer
Answer:Does Claude need it every session (CLAUDE.md)? Only sometimes, for one kind of task (a skill)? Must it happen every time with no judgement (a hook)? What Claude learns on its own as you work goes to auto memory.
2.Why is a hook, not CLAUDE.md, the home for a rule that must never be broken?Show the answer
Answer:CLAUDE.md is context that Claude tries to follow, not enforced configuration. A hook fires on its event whatever Claude decides, and a PreToolUse hook can block the action.
3.What does disable-model-invocation: true change about a skill?Show the answer
Answer:Claude no longer invokes it on its own, and its description stays out of context. Only you can run it with /name, which suits workflows with side effects.
Related deep dives on this site
Sources
Primary sources checked on the research date. Follow them for the current version.