Claude Code now gives you seven ways to change how it behaves. CLAUDE.md, rules, skills, subagents, hooks, output styles, and appending the system prompt. Anthropic laid them all out in a post called Steering Claude Code, and it is a genuinely useful map.
It also quietly confirms a problem I see in nearly every team's .claude directory: people have all seven layers and reach for the wrong one almost every time. A guardrail written as a polite CLAUDE.md line. A one-off prompt template promoted to a full skill. A search task clogging the main thread that should have been a subagent.
The features are not the hard part. Choosing between them is. So here is the same task built four ways, and the rule that falls out of it.
One task, four mechanisms
The task: when I finish work, the code should be formatted and the test suite should pass before anything is called done.
Watch how different the four implementations are, because the difference is the lesson.
As a slash command. You write a prompt template in .claude/commands/wrap-up.md that says "format the changed files, run the tests, and summarise what failed". You type /wrap-up when you want it. It is a saved prompt, nothing more. The model reads it and probably does it. Probably.
As a skill. You build a release-check skill with a SKILL.md plus a helper script that knows your monorepo's package layout, which test groups map to which changed paths, and how to read the coverage output. Claude loads it by name when the work matches, runs the procedure in the main thread where you can watch and steer, and pulls in the helper files only when invoked. This earns its place when the procedure has real logic, not just instructions.
As a subagent. You define a test-analyst subagent. When the suite fails, you hand it the wall of failures and it grinds through logs in its own context, returning a three-line summary instead of dumping 4,000 lines of stack traces into your session. It is isolation: the mess stays in another room and only the conclusion comes back.
As a hook. You add a Stop hook in settings.json that runs the formatter and the test command with code. Not when the model feels like it. Every single time the turn tries to end. If the tests fail, the hook says so and the work does not get to call itself finished.
Same goal. Four completely different tools. Notice that the slash command and the hook look superficially similar (both "run the checks") and are opposites in the one way that matters: one asks, one enforces.
The rule that falls out
Strip away the detail and the choice is about two axes: does it need to be guaranteed, and does it need its own context.
| Mechanism | Reach for it when | The tell |
|---|---|---|
| Slash command | You want a reusable prompt you trigger by hand | "I keep typing the same paragraph at Claude" |
| Skill | There is real domain logic or helper files behind the procedure | "This needs a script and some project knowledge, not just words" |
| Subagent | The work is isolated and its intermediate output would clutter the thread | "I only care about the answer, not the 90 steps to get there" |
| Hook | It must happen every time, enforced by code, not goodwill | "Every time X, always Y" |
That last row is the one people get wrong most. If you ever write "always" or "never" in a CLAUDE.md file, you have found a hook. A prompt instruction is a suggestion the model follows probabilistically, which is the whole argument I made in the hooks guide: if it needs to be guaranteed, it cannot live in a prompt. CLAUDE.md is for facts and conventions, the always-loaded context I covered in the CLAUDE.md piece. It is not where guarantees go to live.
The skill-versus-subagent line trips people up too. Both bundle a procedure. The split is visibility. A skill runs in your main thread because you want to see and guide it. A subagent runs somewhere else because you don't, you just want the summary. If intermediate output is signal, use a skill. If it is noise, use a subagent.
What changed in June, and why it matters here
Two updates this month sharpened two of these tools, and they map cleanly onto the rule above.
Hooks got a brain. As of the mid-June changelog, Stop and SubagentStop hooks can return hookSpecificOutput.additionalContext to feed Claude information and keep the turn going, instead of only being able to hard-block with an error. So the wrap-up hook above can now do better than "tests failed, stopping". It can hand the failure back as context and let the model take another pass. The hook stopped being a brick wall and became a referee that can also talk.
Subagents got depth. Since version 2.1.172, a subagent can spawn its own subagents, up to five levels deep, with foreground chains now respecting the same cap as background ones. That makes the "isolated parallel work" case much stronger. Your test-analyst can fan out to one sub-subagent per failing module and merge the results, all without a single stack trace touching your main window.
Both changes pull in the same direction. Hooks became a better enforcer. Subagents became a better isolator. Neither got better at the other's job, which is exactly why the decision tree still holds. New depth on a tool does not change what the tool is for.
The honest failure mode
Here is what actually happens. Someone learns skills, gets excited, and turns everything into a skill, including the guardrails that should have been hooks and the throwaway prompts that should have been slash commands. Six months later their .claude directory is a museum of half-overlapping mechanisms nobody can reason about, and the one rule that genuinely had to hold every time is a politely-worded line in CLAUDE.md that the model ignores one run in twenty.
The power was never in having seven layers. It is in matching the mechanism to the job, the same discipline I keep coming back to in getting the best out of Claude Code. More layers just means more ways to pick wrong.
So before you build the next clever skill, ask the two questions. Does this need to be guaranteed? Then it is a hook. Does this need its own context? Then it is a subagent. Is it just a prompt you keep retyping? Then it is a slash command, and it was never a skill at all.
Most of the time you do not need the fanciest tool. You need the one that matches the shape of the job.