When you want to automate a task in Claude Code, four different mechanisms show up: hooks, skills, subagents, and MCP. Teams that add instruction after instruction to CLAUDE.md without deciding which one is the right tool — or that delegate every repeating task to a separate subagent — quickly run into both context bloat and unpredictable behavior. This piece answers the "skill vs subagent vs hook" question directly with a decision framework: it shows when each mechanism is the right tool, backed by quotes from the official documentation and real configuration examples.
💡 Pro Tip: Use a hook when you want to enforce a rule, and a skill when you want to remind the model of knowledge — mixing the two produces either a "rule" the model can forget, or a static instruction that gets loaded needlessly on every turn.
Table of Contents
- Four mechanisms in one sentence
- How the four work together
- Decision tree: which box does the question fall into
- When a hook is the right tool — a deterministic, irreversible rule
- Why matcher granularity matters
- When a skill is the right choice — recurring knowledge, loaded on demand
- What invocation control means
- When a subagent is the right choice — keep long output out of the main context
- Restricting with the tools field
- When MCP is the right choice — external systems, live data, authentication
- HTTP or stdio
- 5 common mismatches and how to fix them
- FAQ
- What's the difference between skills, subagents, hooks, and MCP in Claude Code?
- If I want to enforce a rule, should I use a hook or a skill?
- When is CLAUDE.md enough, and when should I move to a skill?
- How much context do unused skills consume?
- Does using a subagent always save context?
- Update (September 2026)
- Conclusion
- Sources
Four mechanisms in one sentence
The fastest way to clarify the difference between the four is to define them with the same sentence pattern.
Hooks are user-defined shell commands, HTTP endpoints, LLM prompts, or subagents that run automatically at specific points in the session — in the documentation's words, they "execute automatically at specific points in Claude Code's lifecycle" (code.claude.com/docs/en/hooks). In other words, a hook does not rely on the model "remembering" — it relies on the system enforcing.
Skills are defined as a SKILL.md file and get added to Claude's toolkit; you can also invoke one directly with /skill-name: "Create a SKILL.md file with instructions, and Claude adds it to its toolkit." The documentation describes the invocation modes in a separate sentence: "Claude uses skills when relevant, or you can invoke one directly with /skill-name" (code.claude.com/docs/en/skills). A skill's body loads only when it's used — unlike CLAUDE.md, it carries almost no cost until long reference material is actually needed: "a skill's body loads only when it's used, so long reference material costs almost nothing until you need it" (same source).
A subagent is a specialist assistant that runs in its own context window and returns only a summary to the main conversation; it's used so that side work you won't reference again — search results, logs, or file contents — doesn't flood the main conversation: "Use one when a side task would flood your main conversation with search results, logs, or file contents you won't reference again" (code.claude.com/docs/en/sub-agents).
MCP (Model Context Protocol) is an open standard for connecting to external tools, databases, and APIs; it comes into play when you want to connect directly instead of copying data from a tool like an issue tracker into the chat: "MCP servers give Claude Code access to your tools, databases, and APIs... Connect a server when you find yourself copying data into chat from another tool" (code.claude.com/docs/en/mcp). If you want a deeper look at the MCP concept, see Claude Code MCP: The AI Plugin Ecosystem via Model Context Protocol.
Mechanism | When it runs | What it solves | Persistence |
|---|---|---|---|
Hook | Automatically at a specific lifecycle point | Deterministic enforcement | Fixed in a settings file |
Skill | On demand (when needed) | Recurring procedure/knowledge | Loads only when used |
Subagent | When delegated, in a separate context | Side work that won't bloat main context | Closes when the task ends |
MCP | As long as it's connected | External system/live data access | Active for the session |
How the four work together
All four mechanisms can take part in a single workflow at once. In a deploy flow, for example: an MCP server pulls which ticket is being closed from the issue tracker, a skill reminds it of the deploy checklist's step order, a subagent scans the build logs and returns only an error summary to the main conversation, and a hook mechanically blocks the deploy command from running outside the production branch at the PreToolUse stage. The four mechanisms don't replace one another — each takes on a different link in the chain. That's why "which one should I use" is often not really a "which" question, but a "which part of this job belongs to which mechanism" question.
Decision tree: which box does the question fall into
Once you line up the four definitions side by side, the question actually gets simpler: "Is this need a deterministic rule, a recurring procedure, a side task that would pollute context, or access to an external system?"
- If you want to enforce a rule (e.g. "a commit message should never break a specific format") → hook. Don't trust the model to remember; trust the system to block.
- If you keep pasting the same instructions/checklist into chat → skill. Almost the same logic applies to creating a subagent: "Define a custom subagent when you keep spawning the same kind of worker with the same instructions" (sub-agents); on the skill side, the sentence "keep pasting the same instructions, checklist, or multi-step procedure into chat, or when a section of CLAUDE.md has grown into a procedure rather than a fact" points to the same signal (skills).
- If a side task would fill the main conversation with search results/logs/file contents → subagent.
- If you need live data or authentication from an external system → MCP.
A need that fails all four of these questions should usually stay in CLAUDE.md — turning everything into a mechanism can be as costly as the mechanisms themselves. If you want to decide where each mechanism fits during the architecture-planning stage, Claude Code Plan Mode: Planning Software Architecture with AI can help you clarify that decision early.
When a hook is the right tool — a deterministic, irreversible rule
Hooks run at three tiers: per session (SessionStart/SessionEnd), per turn (UserPromptSubmit, Stop), and on every tool call, meaning every time inside the agentic loop (PreToolUse/PostToolUse): "per session... per turn... on every tool call inside the agentic loop" (hooks). These three tiers let you choose a hook not by "when" but by "at what reliability level."
The canonical example is blocking an irreversible action. In the documentation's example, a PreToolUse hook blocks Bash calls whose command contains rm -rf by returning permissionDecision: "deny": "returns a permissionDecision of \"deny\" if it contains rm -rf" (same source). This is the concrete example of stopping something mechanically, without leaving it to the model's "decision":
1{2 "hooks": {3 "PreToolUse": [4 {5 "matcher": "Bash",6 "hooks": [7 {8 "type": "command",9 "command": "scripts/block-dangerous-rm.sh"10 }11 ]12 }13 ]14 }15}Which file you define a hook in determines its scope, and their shareability differs:
Level | File | Sharing |
|---|---|---|
User | ~/.claude/settings.json | Not shared, local machine only |
Project | .claude/settings.json | Can be committed, shared with the team |
Project (local) | .claude/settings.local.json | Gitignored, personal |
Enterprise | Managed policy settings | Enforced organization-wide |
Plugin | hooks/hooks.json | Ships with the plugin while it's active |
Skill | SKILL.md frontmatter | Defined in the skill file, travels with it |
Source: ".claude/settings.json ... Single project ... Yes, can be committed to the repo" (hooks). For the full workings of the pre-commit/post-commit scenario, there's already a dedicated deep-dive guide: Claude Code Hooks: Pre-Commit and Post-Commit Automation.
Why matcher granularity matters
When defining hooks at the PreToolUse/PostToolUse level, the matcher field determines which tool calls trigger the hook. In the example above, matcher: "Bash" targets only the Bash tool; binding a hook to an overly broad matcher (e.g. matching all tools) runs an unnecessary command on every tool call and adds latency, while an overly narrow matcher can miss the exact scenario the rule was meant to protect. Answering "which tool call should this rule apply to" clearly when choosing the matcher protects both performance and reliability.
When a skill is the right choice — recurring knowledge, loaded on demand
Skills gain scope based on file location. User-wide skills under ~/.claude/skills/ work across all your projects; project skills under .claude/skills/ are committed and travel with your team: "~/.claude/skills/<skill-name>/SKILL.md ... All your projects on this machine..." / ".claude/skills/<skill-name>/SKILL.md ... Sessions in this repository. Commit it so your team gets it too" (skills).
A simple SKILL.md skeleton looks like this:
1---2description: Runs the pre-deploy checklist. Use when the user says "deploy" or "ship it."3---4 5Deploy Checklist6 7Steps:8 91. Build verification102. Health check113. Cache purgeSkills follow the open standard called Agent Skills, which works consistently across multiple AI tools, and Claude Code extends it with additional features like invocation control, running inside a subagent, and dynamic context injection: "Claude Code skills follow the Agent Skills open standard, which works across multiple AI tools. Claude Code extends the standard with additional features like invocation control... subagent execution... and dynamic context injection" (same source). This is the core architectural difference that separates a skill from CLAUDE.md's "always loaded" nature.
What invocation control means
Invocation control means you decide how a skill gets triggered: you can let Claude activate it on its own judgment based on the flow of the conversation, or you can make the skill invokable only manually, via /skill-name. The second mode is preferred when you want to prevent a skill from accidentally activating and triggering an unexpected procedure — especially for procedures whose consequences are hard to undo, like a deploy or a data cleanup.
When a subagent is the right choice — keep long output out of the main context
The documentation lists five core benefits of using subagents: preserving context, enforcing rules through tool restrictions, reusing configuration across projects, specializing behavior with focused system prompts, and controlling cost by routing to cheaper/faster models (e.g. Haiku): "Preserve context... Enforce constraints... Reuse configurations... Specialize behavior... Control costs by routing tasks to faster, cheaper models like Haiku" (sub-agents).
When Claude decides which subagent to delegate to, it looks at the subagent's description field. These descriptions consume context, so they should stay short; detail should go only into that subagent's system prompt, which loads only while that subagent is running: "Claude uses each subagent's description to decide when to delegate tasks... Those descriptions take up context, so keep them short... move detail into each subagent's system prompt, which only loads when that subagent runs" (same source).
1---2name: log-triage3description: Scans long log files and returns only an error summary.4tools: Read, Grep5model: haiku6---7 8You are a log-triage specialist. Return only a short summary of the9error lines; do not write the raw log content back.The built-in General-purpose subagent is chosen for complex, multi-step tasks that require both exploration and action (code changes): "Claude delegates to general-purpose when the task requires both exploration and modification, complex reasoning to interpret results, or multiple dependent steps" (same source) — this is the concrete application of the principle "don't let long output enter the main context." You can also find the scenario of coordinating multiple subagents in parallel in Claude Code Multi-Agent Teams: Developing with Parallel AI Agents.
Restricting with the tools field
In the log-triage example above, the tools: Read, Grep line states that the subagent can only read and search — it cannot write files or run commands. This is the concrete counterpart of the "Enforce constraints" benefit: when you want to lock a subagent to a specific purpose, explicitly limiting which tools it can access is a far more reliable guarantee than writing "don't modify files" in the system prompt — because the latter is an instruction, the former is a constraint.
When MCP is the right choice — external systems, live data, authentication
MCP use cases cluster around external system integration: implementing features from issue trackers, analyzing monitoring data, querying databases; an MCP server can also act as a channel that pushes messages into a session from an external event source (e.g. Telegram/Discord/webhook): "Implement features from issue trackers... Analyze monitoring data... Query databases... an MCP server can also act as a channel that pushes messages into your session" (mcp).
MCP servers are set up via four connection types: remote HTTP (recommended), remote SSE (deprecated — only for services that still offer SSE), local stdio (for tools that need direct system access), and remote WebSocket (a persistent bidirectional connection): "HTTP servers are the recommended option for connecting to remote MCP servers" / "The SSE (Server-Sent Events) transport is deprecated. Use HTTP servers instead, where available" / "Stdio servers run as local processes on your machine. They're ideal for tools that need direct system access" / "WebSocket servers hold a persistent bidirectional connection" (same source).
1{2 "mcpServers": {3 "issue-tracker": {4 "type": "http",5 "url": "https://mcp.example.com/issues"6 }7 }8}Stdio servers are not a remote endpoint — they are local processes that run on your own machine; the documentation defines it this way: "Stdio servers run as local processes on your machine. They're ideal for tools that need direct system access or custom scripts" (same source). For how MCP's plugin ecosystem expands on this, see Claude Code MCP: The AI Plugin Ecosystem via Model Context Protocol.
HTTP or stdio
A remote HTTP connection is the recommended option because authentication, versioning, and shared infrastructure management stay on the server side; team members connect to the same MCP server with the same configuration. Stdio, on the other hand, is necessary for scenarios that need direct system access — dependent on a filesystem or a local tool — in which case the server runs as a local process that Claude Code launches. Mixing the two connection types (e.g. trying to serve a local filesystem tool over remote HTTP) adds an unnecessary network layer; the right choice depends on where the data lives.
Once you've made the choice, pay attention to two configuration details, because both fail silently with the wrong result. First, the -- separator when adding a stdio server from the command line: the documentation calls this out as a separate warning — "the -- (double dash) separates Claude's own options, such as --transport, --env, and --scope, from the command and arguments that run the server. Everything after -- is passed to the server untouched" (same source). If you forget the separator, flags meant for the server get mistaken for Claude Code's own options; if you include it, everything after it is passed to the server as-is.
Second, skipping the type field in .mcp.json. Claude Code reads an entry with no type field as a stdio server; so giving only a url for a remote server without writing type is a configuration mistake, and you'll hit command: expected string, received undefined (same source). Because the error text looks command-related, finding the real cause (a missing type) takes time — always write the type field explicitly, as in the example above.
5 common mismatches and how to fix them
- Using a skill instead of a hook: "always enforce the commit message format" is a rule, not a procedure — you need the system to block it, not the model to "remember" it. Fix: move it into a
PreToolUse/PostToolUsehook. - Using a subagent instead of a skill: a simple, recurring piece of knowledge is a procedure, not something that needs a separate context window — a skill's body already loads only when used. Fix: bring it down into a
SKILL.md. - Using a hook or skill instead of MCP: trying to reach live, authenticated external data with a static instruction doesn't work — MCP exists exactly for connecting to a "database, an API." Fix: connect the relevant MCP server.
- Doing research in the main conversation instead of using a subagent: long search/log output bloats the main context and degrades the quality of later turns. Fix: delegate the side task to a subagent.
- Turning everything into a mechanism: a need that can't get a clear "yes" to any of the four questions should usually stay as one sentence in CLAUDE.md — adding a mechanism is a cost in itself.
GOLDEN TIP
The most valuable insight in this article
This tip holds the article's most important takeaway.
Easter Egg
You found a hidden gem!
There's a hidden detail in this section. Want to uncover it?
Reader Reward
Below is a checklist you can use when applying the four mechanisms from this article to your own project. Match each line against the items in your own CLAUDE.md and decide which one should really be a hook, a skill, a subagent, or MCP.
FAQ
What's the difference between skills, subagents, hooks, and MCP in Claude Code?
A hook is a mechanism that runs automatically at a specific lifecycle moment and can be deterministically enforced; a skill is a file loaded on demand that carries recurring knowledge or a procedure; a subagent is a delegation unit that runs in its own context window and returns only a summary to the main conversation; MCP is an open protocol for connecting to external tools, databases, and APIs. Each of the four answers a different question: a hook asks "does this rule always apply," a skill asks "am I reminding it of this knowledge over and over," a subagent asks "will this work pollute the main conversation," and MCP asks "is this data coming from outside."
If I want to enforce a rule, should I use a hook or a skill?
Use a hook. A skill's body loads only when Claude "decides to use" that skill, meaning it depends on the model's judgment; a hook, on the other hand, runs automatically and deterministically at a specific point inside the agentic loop (like PreToolUse), without needing the model's decision. If you want to block an irreversible action (deleting a file, a dangerous command), the only right tool is a hook.
When is CLAUDE.md enough, and when should I move to a skill?
CLAUDE.md loads in full every session, so it's suited for short, always-applicable general instructions. Move a section to a skill once it turns into a multi-line procedure, a checklist, or reference material you rarely need — a skill's body loads only when used, so unlike CLAUDE.md it doesn't carry a cost on every turn.
How much context do unused skills consume?
A skill's short description (frontmatter) stays in context at all times so Claude can decide when to activate it; but the actual body loads only when the skill is used. So the context cost of an "unused" skill is just its short description, not its body — but once a lot of skills pile up, the sum of these short descriptions can also become noticeable.
Does using a subagent always save context?
No, it only saves context when the side task's output is long and won't be referenced again. Delegating a short, single-step task to a subagent adds an extra layer of delegation and description cost; the real benefit is isolating long outputs — "search results, logs, or file contents you won't reference again" — from the main conversation.
Update (September 2026)
The body of this article describes Claude Code behavior as of March 12, 2026. Verified changes related to the four mechanisms since that date are:
- The
/skill-doctorcommand was added — it reports loaded-but-unused skills and the load they add to context every turn; in an interactive session it's opened from the "Stats" tab of the/pluginmanager. Released the week of August 31–September 4, 2026 (source: code.claude.com/docs/en/whats-new/2026-w36). - Hooks can now call MCP tools directly — the
type: "mcp_tool"handler type was added on April 23, 2026 with v2.1.118; meaning a hook handler can now also be an MCP tool call, in addition to a command, HTTP endpoint, prompt, and subagent (source: code.claude.com/docs/en/changelog). - Subagents started running in the background by default — as of v2.1.198, subagent calls no longer block the main session (source: code.claude.com/docs/en/whats-new/2026-w27).
- The
CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTHenvironment variable was added — the fixed 2,048-character cutoff on MCP tool descriptions can now be changed on a per-session basis (source: code.claude.com/docs/en/changelog). - Stdio MCP servers started receiving
CLAUDE_PROJECT_DIR— v2.1.139, May 11, 2026: "MCP stdio servers now receiveCLAUDE_PROJECT_DIRin their environment, matching hooks." This means a stdio server can now resolve paths relative to the project root; this behavior didn't exist when the body of this article was written (source: code.claude.com/docs/en/changelog).
None of these five changes alter the article's decision framework — they only improve the observability and configuration flexibility of hooks/skills/subagents/MCP.
Conclusion
There's one question that separates the four mechanisms: is this need a deterministic rule (hook), recurring knowledge (skill), a side task that would pollute context (subagent), or access to an external system (MCP)? Asking this question every time a new automation need comes up largely prevents CLAUDE.md bloat and the unpredictability that comes from picking the wrong mechanism. To go deeper on hooks, see Claude Code Hooks: Pre-Commit and Post-Commit Automation; for the MCP ecosystem, see Claude Code MCP: The AI Plugin Ecosystem via Model Context Protocol; for coordinating parallel subagents, see Claude Code Multi-Agent Teams: Developing with Parallel AI Agents; for architectural decisions during planning, see Claude Code Plan Mode: Planning Software Architecture with AI; and to see where these tools fit in the context of IDE integration, take a look at Claude Code IDE Integration: VS Code, JetBrains, and Terminal.
Sources
- Hooks reference — code.claude.com — hook lifecycle points, settings file levels, and the
PreToolUsedeny example. - Skills — code.claude.com — SKILL.md structure, scope levels, and the Agent Skills open standard.
- Sub-agents — code.claude.com — subagent benefits, the description field, and the General-purpose subagent definition.
- MCP — code.claude.com — connection types, use cases, and
.mcp.jsonconfiguration rules. - Changelog — code.claude.com — release notes and the
CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTHentry. - What's new, Week 36 2026 — code.claude.com — addition of the
/skill-doctorcommand.
Tags
iOS Development News
Weekly Swift tips, SwiftUI tricks and iOS best practices. No spam, only valuable content.
We respect your privacy. You can unsubscribe at any time.

