Your Claude Code setup is getting messy. There's a CLAUDE.md that grows every time Claude makes a mistake, a pasted prompt you reuse daily, a rule Claude breaks one run in ten, and a vague sense that you should be using "subagents" because everyone mentions them. Which of these belongs where?
Short answer: put what Claude should always know in CLAUDE.md, what it should do on request in a skill, what must happen every time in a hook, what is noisy work in a subagent, and what lives outside your machine behind MCP. The rest of this post is how to tell those apart in practice, with the context cost of each, and a small setup you can copy. I checked the behaviors below against Anthropic's Claude Code docs on 2026-10-08.
This is the decision guide. For how to write a skill file and debug one that won't fire, see how to write your first Claude skill. I won't repeat that here.
Which Claude Code feature should I use? The cheat sheet
| You want... | Use | Why |
|---|---|---|
| Claude to always know your build command and conventions | CLAUDE.md | Loads every session |
A repeatable task you trigger by name, like /release-notes | Skill | Loads on demand |
| Reference material Claude needs only sometimes (API style guide) | Skill | Costs almost nothing until used |
A rule that must hold every time (never edit .env) | Hook | Deterministic, doesn't depend on Claude remembering |
| Formatting or linting after every edit | Hook | Same: runs on the event, no judgment needed |
| A research task that reads 40 files but you want a 10-line answer | Subagent | Separate context window |
| Claude to read your database, Slack, or issue tracker | MCP server | Connects an external system |
| The same setup in five repositories | Plugin | Packages the above |
| A different tone or response format all session | Output style | Changes how Claude answers, not what it knows |
If you remember one row, remember the hook one. Everything else is a request that Claude may or may not honor perfectly. A hook is code.
When does CLAUDE.md beat a skill?
When the information is true on every task. Build commands, folder layout, "we use pnpm", "never mock the database in tests". The docs' rule of thumb is to keep it under 200 lines, because the whole file is in context on every request. The docs also say the more specific and concise your instructions are, the more consistently Claude follows them, so a bloated file works against you.
The test I'd use: would this line help on a task unrelated to the one you're doing now? If not, it's a skill, or a path-scoped rule in .claude/rules/, which the docs say loads only when Claude works with matching files.
Docs-recommended trigger for adding to CLAUDE.md: Claude gets a convention or command wrong twice. Not once, twice. If you add a line for every one-off slip, you rebuild the 600-line file nobody follows. Our guide to writing a CLAUDE.md for any project covers what to put in it, and the project memory lesson covers how it loads.
When is a skill better than a slash command or a pasted prompt?
A slash command used to be a Markdown file in .claude/commands/. The docs now say commands have been merged into skills: both create the same /name, old command files still work, and a skill wins if the names collide. So the practical question is no longer "command or skill", it's "do I want the extras?" Skills give you a folder for supporting files, frontmatter that controls who can invoke them, and automatic loading when your request matches the description.
Reach for one when you notice you've pasted the same playbook into chat three times. The docs list that exact trigger.
Two details that decide design:
- Descriptions are always in context; bodies aren't. Claude sees each skill's name and description every request and loads the full text only when the skill is used. So fifty skills isn't free, but it's cheap. Skills with
disable-model-invocation: truecost nothing until you call them. - A skill is advice, not enforcement. Claude follows the instructions with judgment. The docs say that if Claude skipped a rule that must hold every time, move the rule into a hook.
When do you need a hook instead of an instruction?
When "usually" isn't good enough. Hooks are shell commands (or HTTP calls, MCP tool calls, prompts, or a subagent) that Claude Code runs at lifecycle events: before a tool call, after an edit, when a session starts, when Claude needs your input. The docs call this deterministic: the action always happens instead of relying on the model to choose to run it.
The exit code is the mechanism worth knowing. For a command hook on an event that can block, such as PreToolUse, exit 2 blocks the action and your stderr message goes back to Claude as feedback so it can change course. Exit 0 lets it proceed. Exit 1 does not block, which catches people out: the action goes ahead and you just see a hook error notice. If you mean to enforce something, it's exit 2.
Good hook jobs, straight from the docs: auto-format after edits, block edits to protected files, desktop notification when Claude is waiting on you, re-inject reminders after context compaction. Bad hook jobs: anything needing judgment. That's what skills are for.
Security note, because hooks run with your permissions: a hook is a script you wrote running automatically. Read any hook you copy from someone else the way you'd read an install script. The deep dive is in the hooks lesson.
When should you hand work to a subagent?
When the work is noisy and you only want the answer. A subagent runs in its own context window with its own system prompt and tool list. It starts fresh: it doesn't see your conversation. When it finishes, only its summary comes back. So "find every place we call the payments API and tell me which are missing retries" can read forty files without bloating your main session.
What the docs say about the edges:
- Built-in ones exist already: Explore and Plan (read-only), and general-purpose. You may not need a custom one.
- A custom subagent is a Markdown file in
.claude/agents/(project) or~/.claude/agents/(all projects). Onlynameanddescriptionare required.toolsrestricts what it can do. - Each subagent makes its own requests and counts toward your usage limits. Many detailed results can also eat your main context when they return.
- Subagents can spawn subagents, by default up to three layers deep, with up to 20 running at once.
Use one when a side task floods the conversation, or when you want a differently-instructed worker, like a reviewer that is not allowed to edit. Don't use one for a three-line question. The multi-agent lesson covers parallel patterns. Limits and defaults change between versions, so check the docs for yours.
When do you need MCP, and what does it cost?
When Claude needs to reach something that isn't on your disk: a database, GitHub, Slack, a browser. MCP is the connection. It gives Claude tools, and a skill can then teach Claude how to use them well, such as your schema and your query conventions. They pair; they don't compete. If MCP itself is new to you, start with what MCP is, then the MCP servers lesson for Claude Code specifics.
On context: per the docs, MCP loads tool names at session start and defers full schemas until a tool is needed, with tool search on by default. Run /mcp to see server status and /context all to see what each tool costs. Disconnect servers you aren't using.
What does each option cost in context?
This is the table I'd pin above your desk. It's from Anthropic's feature overview, condensed.
| Feature | When it loads | Cost |
|---|---|---|
| CLAUDE.md | Session start, full text | Every request |
| Skill | Description at start; body when used | Low |
Skill with disable-model-invocation | Only when you call it | Zero until used |
| MCP | Tool names at start; schemas on demand | Low until used |
| Subagent | When spawned | Isolated, but uses usage |
| Hook | On its event | Zero unless it returns output |
Worked setup: one small project, four pieces
Say you maintain a web app. You want Claude to know the stack, write release notes on request, never touch lockfiles or .env, and review changes without cluttering your session. Here's the whole thing, nothing exotic.
1. CLAUDE.md (six lines, because only always-true things go here):
# Project notes
- Stack: Next.js, TypeScript, pnpm. Use pnpm, never npm.
- Run `pnpm test` before suggesting a commit is ready.
- Components live in src/components, one per file.
- Ask before adding a dependency.
2. A skill for the thing you trigger by name: release-notes, built in the first-skill walkthrough. It lives in .claude/skills/release-notes/SKILL.md.
3. A hook for the rule that must hold. Save as .claude/hooks/protect-files.sh:
#!/bin/bash
# Blocks edits to files that should never be hand-edited by an agent.
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Blocked: $FILE_PATH matches protected pattern '$pattern'. Ask the user before touching it." >&2
exit 2
fi
done
exit 0
Run chmod +x .claude/hooks/protect-files.sh, then register it in .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
This follows the pattern in Anthropic's hooks guide. I tested the script itself by piping it two sample inputs: an edit to /project/.env printed the Blocked: message and exited 2, and an edit to /project/src/app.py exited 0. The settings JSON parses. I did not run it inside a live Claude Code session, so after you set it up, ask Claude to add a comment to .env and confirm it's refused. It needs jq installed (brew install jq on macOS). Type /hooks to confirm it's registered.
4. A subagent for review. Save as .claude/agents/diff-reviewer.md:
---
name: diff-reviewer
description: Reviews uncommitted changes for bugs, missing error handling and risky edits. Use proactively before committing.
tools: Read, Grep, Glob, Bash
model: sonnet
---
You review code changes. Run `git diff HEAD`, read the surrounding code for any file that looks risky, and report only problems that would matter in production.
Format: a short list, most serious first. For each item give the file, the line, what breaks, and a one-line fix. If you find nothing serious, say so in one sentence. Do not edit files.
The frontmatter parses, and the field names (name, description, tools, model) match the docs' reference. Invoke it with "use the diff-reviewer agent on my changes". Note the instruction "do not edit files" is a request. If you need it enforced, drop Edit and Write from the tools list, which is already the case here, since tools is an allowlist.
That last point is the whole post in miniature. The allowlist is enforcement. The sentence in the prompt is a request.
Common mistakes
- Putting enforcement in CLAUDE.md. "Never edit .env" there is a suggestion. Use the hook.
- Using a subagent for a small question. You pay for a fresh context and a summary to read back.
- One giant skill. Split by task, give each a distinct description, otherwise two skills compete for the same request.
- A hook that uses
exit 1to block. It doesn't. Useexit 2. - Adding everything on day one. The docs suggest the opposite: add each piece when a trigger appears, like Claude getting something wrong twice, or you pasting the same prompt a third time.
If you are weighing Claude Code against other tools at all, Claude Code vs Cursor vs Copilot is the broader comparison.
Sources: Anthropic's Extend Claude Code overview, skills, hooks guide and subagents docs, all read on 2026-10-08. Claude Code changes quickly; check the docs for your installed version.



