Contacts
Follow us:
Get in Touch
Close

Contacts

Türkiye İstanbul

info@thinkpeak.ai

Claude Code Hooks vs Skills vs Subagents: When to Use Each

Green low-poly robot at a desk with a hook, a binder and a helper robot, representing Claude Code hooks, skills and subagents

Claude Code Hooks vs Skills vs Subagents: When to Use Each

The choice between Claude Code hooks vs skills vs subagents comes down to one question: who decides when the thing runs, and where does its output go? A hook is a script Claude Code runs on a lifecycle event, every time, without the model deciding. A skill is a folder of instructions Claude loads into the current conversation when your task matches its description or when you type its name. A subagent is a separate Claude worker with its own context window that does a side task and returns only a summary. Pick the wrong one and you get rules that are quietly ignored, a context window full of noise, or a bill that grows faster than the work. This guide explains how each mechanism works, compares them side by side, shows working files for all three, covers costs and limits from Anthropic’s own documentation, and walks through a real production repository that uses all three to publish a blog post every day.

Claude Code hooks vs skills vs subagents: the short answer

If you only remember one rule, make it this one from Anthropic’s feature guide: an instruction in CLAUDE.md or a skill “is a request, not a guarantee,” while a hook that blocks the action “is enforcement” (Claude Code docs: Extend Claude Code). Everything else follows from who is in control.

  • Use a hook when something must happen the same way every time and needs no judgment: format after every edit, block writes to secret files, log every command, refuse to stop until a record is written.
  • Use a skill when Claude needs a procedure or reference material only sometimes: a deploy checklist, a release playbook, your brand style guide, a daily publishing routine.
  • Use a subagent when a side task would flood the main conversation with output you will not read again: searching a large codebase, reading twenty web pages, running a long test suite, reviewing a diff with fresh eyes.

The three are not rivals. They sit at different points of Claude’s working loop, and a mature setup uses all three together, plus CLAUDE.md for the facts every session needs. The rest of this article is about the edges: the cases where two mechanisms look interchangeable but behave very differently in cost, reliability and context use. Those edges are where most teams lose time, because the failure modes are silent. A skill that never triggers does not raise an error; a subagent that burns tokens does not warn you; a hook with the wrong exit code lets the action through and only prints a notice.

How each mechanism works under the hood

Hooks: code that runs on events

Hooks are configured in settings files, not in prompts. A hook names an event, an optional matcher, and a handler. Claude Code supports five handler types: a shell command, an http POST of the event JSON, an mcp_tool call, a single-turn prompt to a Claude model, and an experimental agent handler that can use tools to verify a condition (Claude Code hooks reference). Events cover the whole session lifecycle, including SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, SubagentStart, SubagentStop, PreCompact and Stop. The exit code carries the decision: 0 means success, 2 means a blocking error whose stderr text becomes the reason, and any other code is a non-blocking error that lets the action proceed.

Skills: instructions loaded on demand

A skill is a directory containing a SKILL.md file with YAML frontmatter and Markdown instructions, plus any scripts or reference files it needs. Anthropic describes the loading model as progressive disclosure: at startup only each skill’s name and description sit in the system prompt, the body loads when Claude judges the skill relevant, and bundled files load only as needed (Anthropic Engineering: Equipping agents with Agent Skills). Skills run inside the conversation you are already in, so whatever they make Claude read lands in your main context.

Subagents: separate workers with their own context

Anthropic’s documentation states that “each subagent runs in its own context window with a custom system prompt, specific tool access, and independent permissions” (Claude Code docs: subagents). A subagent starts fresh: it does not see your conversation history, the skills you invoked, or the files Claude already read. It receives its own system prompt, the task the main agent writes for it, and, for most agent types, CLAUDE.md and git status. When it finishes, only its final report returns to the main conversation. That isolation is the whole point, and it is also the main source of mistakes, because the subagent knows only what the brief tells it.

Side-by-side comparison

The table below condenses the differences that matter when you decide where a piece of behavior belongs. The context-cost rows come from Anthropic’s per-feature loading table (Extend Claude Code); the file locations and frontmatter from the reference pages for each feature.

Aspect Hook Skill Subagent
What it is Script, HTTP call, MCP tool call, prompt or agent run on an event Folder with SKILL.md instructions and optional files Separate Claude worker with its own context and tools
Who triggers it Claude Code, on a lifecycle event You with /name, or Claude when the description matches Claude via the Agent tool, or you by asking for it
Deterministic? Yes, fires on every matching event No, Claude interprets the steps No, Claude decides what to delegate and how
Context cost Zero unless the hook returns output Description every request; full body when used Isolated; only the summary returns
Can block an action Yes (exit 2 or a deny decision) No No
Where it lives .claude/settings.json, user settings, plugin hooks/hooks.json, skill or subagent frontmatter .claude/skills/<name>/SKILL.md, ~/.claude/skills/, plugins .claude/agents/*.md, ~/.claude/agents/, plugins
Best for Guardrails, formatting, logging, notifications, completion checks Procedures, checklists, reference docs, repeatable workflows Wide searches, research, verbose test runs, independent review
Main failure mode Wrong exit code lets the action through Vague description, skill never loads Thin brief, wasted tokens, confident wrong summary

Two rows deserve emphasis. First, only hooks can stop Claude from doing something. A skill can say “never edit .env” and Claude will usually comply, but usually is not a control. Second, only subagents keep intermediate work out of your main window. A skill that tells Claude to read forty files still puts forty files into your conversation.

When to use each one: decision rules that hold up

Anthropic publishes a list of triggers for adding each feature, and it is the most practical decision aid available. Paraphrasing the relevant rows of the build-your-setup-over-time table: if you keep typing the same prompt to start a task, save it as a skill; if you paste the same playbook into chat for the third time, capture it as a skill; if a side task floods the conversation with output you will not reference again, route it through a subagent; if you want something to happen every time without asking, write a hook.

In practice, four more rules hold up well:

  1. If breaking the rule costs money or data, it is a hook. Deleting files, writing secrets, pushing to a protected branch, emailing customers. Put the rule in a PreToolUse hook and keep a one-line reminder in CLAUDE.md so Claude understands why it was blocked.
  2. If the work needs judgment, it is not a hook. A hook cannot decide whether an article reads well. Use a skill that defines the quality bar and let Claude apply it, then add a hook only for the parts that can be checked mechanically.
  3. If you would not read the intermediate output, it is a subagent. Raw search results, test logs and crawl output belong in a separate window. If you need to see every step, keep it in the main session.
  4. If the same subagent brief keeps growing, part of it is a skill. A subagent can preload skills through its skills: field, so the reusable knowledge goes in the skill and the subagent definition stays short.

Who this split is not for: if you only use Claude Code for occasional one-off questions, none of the three is worth configuring yet. Start with a short CLAUDE.md and add mechanisms only when one of the triggers above actually happens twice.

Step by step: build a hook, a skill and a subagent

1. A PreToolUse hook that blocks writes to secret files

Add this to .claude/settings.json in your repository. The matcher accepts a pipe-separated list of tool names, and the handler receives the event JSON on stdin (Claude Code hooks guide).

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          { "type": "command",
            "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-env.sh" }
        ]
      }
    ]
  }
}

Then the script at .claude/hooks/protect-env.sh:

#!/usr/bin/env bash
input=$(cat)
path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')
case "$(basename "$path")" in
  .env|.env.*)
    echo "Blocked: $path. Secrets live in the environment, not in files." >&2
    exit 2 ;;
esac
exit 0

Make it executable with chmod +x .claude/hooks/protect-env.sh, then run /hooks inside Claude Code to confirm it is registered. Exit code 2 is what blocks; exit 1 does not, which is the single most common hook bug. If you prefer structured output, exit 0 and print a JSON object with permissionDecision set to deny, allow, ask or defer, as the hooks reference describes.

2. A skill for a repeatable procedure

Create .claude/skills/release-notes/SKILL.md:

---
name: release-notes
description: Draft customer-facing release notes from merged PRs since the last tag. Use when asked for release notes or a changelog.
disable-model-invocation: true
---
1. Run `git describe --tags --abbrev=0` to find the last tag.
2. List merged PRs since that tag with `git log <tag>..HEAD --merges --oneline`.
3. Group changes into Added, Changed, Fixed. One line each, plain English.
4. Leave out internal refactors and dependency bumps.
5. Write the result to RELEASE_NOTES.md and show it.

Type /release-notes to run it. Setting disable-model-invocation: true means Claude never triggers it on its own and its description stays out of context until you call it, which the skills documentation recommends for anything with side effects. Drop that line for reference skills, such as a style guide, that Claude should load whenever they are relevant.

3. A read-only research subagent

Create .claude/agents/source-checker.md:

---
name: source-checker
description: Verifies factual claims in a draft against their linked sources. Use after a draft is written and before publishing.
tools: Read, Grep, WebFetch
model: sonnet
---
You check facts. For each number or quote in the file you are given,
open the linked source and confirm it says the same thing.
Return a table: claim | source | verdict (ok, wrong, not found) | note.
Do not edit any file.

The tools line is an allowlist, so this agent cannot write or run shell commands even if its instructions drift. The model line lets a cheaper model do bounded work. Ask Claude to “use the source-checker agent on draft.md” and the verification runs in a separate window; your main session receives only the table.

How hooks, skills and subagents combine (with CLAUDE.md and MCP)

The mechanisms are designed to nest. A skill can declare context: fork to run its whole body inside a subagent, with the agent field choosing which subagent type runs it. A subagent can preload skills through its skills: field, in which case the full skill content is injected at launch rather than only the description (subagents docs). Both skills and subagents can carry their own hooks in frontmatter, scoped to the time the skill or subagent is active. And hooks can themselves run a prompt or an agent when a check needs judgment.

Two neighbors complete the picture. CLAUDE.md holds what Claude must know in every session: build commands, conventions, “never do X” rules. Anthropic’s guidance is to keep it under 200 lines and move reference material into skills, because CLAUDE.md is loaded on every request (Claude Code docs: memory and CLAUDE.md). MCP servers give Claude tools for outside systems such as a database, Slack or a CRM; a skill then teaches Claude how to use those tools well (Claude Code docs: MCP). When the same setup is needed in a second repository, a plugin packages skills, hooks, subagents and MCP servers into one installable unit (Claude Code docs: plugins).

A useful mental model: CLAUDE.md is the employee handbook, skills are the binders on the shelf, subagents are colleagues you hand a task to, hooks are the door locks and smoke alarms, and MCP is the phone line to other departments. If you are designing a larger agent system around these parts, our guide to orchestrating AI agents for business covers the same split between rules, roles and controls at the business-process level.

Costs and limits, with a worked example

For budgeting, Anthropic reports that across enterprise deployments the average Claude Code cost is around $13 per developer per active day and $150 to $250 per developer per month, with 90 percent of users below $30 per active day (Claude Code docs: manage costs). The three mechanisms push that number in different directions.

  • Hooks cost nothing in tokens unless they return output into the conversation. The same costs page gives the example of a hook that greps a 10,000-line log for errors so Claude receives hundreds of tokens instead of tens of thousands.
  • Skills cost their description on every request and their body once loaded. The skills docs cap each description at 1,536 characters in the listing and recommend keeping SKILL.md under 500 lines; after auto-compaction, each re-attached skill keeps its first 5,000 tokens within a shared 25,000-token budget (skills docs).
  • Subagents keep your main window small but send their own requests, which count toward the same usage limits (subagents docs). By default a subagent can nest up to three layers below the main conversation, and spawning a 21st concurrent subagent fails with “Concurrent subagent limit reached.”

Agent teams, which run several full Claude Code instances, are the expensive end of the scale: the costs page says they use approximately 7x more tokens than standard sessions when teammates run in plan mode (manage costs).

Worked example: where to put a log review

Say your nightly job writes a 10,000-line log and you want Claude to explain the failures. Option A, a skill that tells Claude to read the log: the whole file enters your main context and stays there for every following request. Option B, a subagent that reads the log: your main window stays clean, but the subagent still pays to read the full file once, then returns a short summary. Option C, a hook or script that filters to lines containing ERROR first: Claude sees only the failures, which is the case the costs page measures as hundreds of tokens instead of tens of thousands. The cheapest correct design is C feeding B only when the filtered output is still long. The general lesson: do mechanical reduction in code, and spend model tokens only on the part that needs reasoning. For the economics of running many agents at once, see our breakdown of the cost of running multi-agent systems.

A real example: the repository that publishes this blog

This article was researched, written, quality-checked and published by a scheduled Claude Code session, and the repository behind it is a compact case study in where each mechanism belongs. There is no web app and no database: just a git repository, a short CLAUDE.md, three skills, two hooks, and a few Node scripts.

  • CLAUDE.md holds the facts every run needs: the site, the four categories, the voice, the commands, and ten numbered rules such as “one post per run” and “never invent statistics.”
  • Three skills hold the procedures: write-post (daily: pick a keyword, research, write, run the quality gate, publish, record, push), refill-keywords (weekly) and weekly-review (weekly edits to the skills based on what went wrong). Each description says exactly when to use it, so the scheduled prompt only has to name the job.
  • A PreToolUse hook blocks any edit to .env files, because secrets exist only in the cloud environment and the repository must stay safe to make public.
  • A Stop hook refuses to let the session end if a post file was written today but the run log has no row for today. It exits 2 once with a reason, then lets the session end on the second pass so it cannot loop forever.

Why this split? The publishing procedure needs judgment at every step, so it is a skill. The two rules that must never be broken, no secrets in files and no unrecorded runs, are hooks, because an unattended run has nobody to catch a skipped step. Research could be moved into a subagent to keep the writing context clean; it currently runs in the main session because the writer needs the sources it found. If you plan a similar unattended setup, the human-in-the-loop guide covers where approvals still belong.

Common mistakes and how to avoid them

  1. Exiting 1 to block. Only exit code 2 blocks; exit 1 is treated as a non-blocking error and the tool call goes ahead (hooks reference). Test every blocking hook by deliberately triggering it once.
  2. Writing guardrails as prose. “Never push to main” in CLAUDE.md is a preference. If it matters, add a hook or a permission deny rule. As Anthropic’s steering guide puts it, “The model choosing to run a formatter is different from the formatter running automatically” (Claude blog: steering Claude Code).
  3. Vague skill descriptions. Claude chooses skills by matching your task to descriptions. “Helps with docs” never fires; “Drafts release notes from merged PRs. Use when asked for release notes” does. Put the trigger phrase first, because long descriptions are truncated.
  4. Assuming allowed-tools restricts tools. In a skill, it pre-approves tools for the turn; it does not remove others. Use disallowed-tools, permission rules or a hook to restrict.
  5. Thin subagent briefs. A subagent sees none of your conversation. Write the goal, what is already ruled out, which files matter and what shape the answer should take, or you will pay for it to rediscover context.
  6. Spawning subagents for small lookups. Reading one known file is cheaper inline. Delegate when the work is wide, verbose or independent.
  7. Stop hooks without an escape. A Stop hook that always exits 2 traps the session. Check stop_hook_active in the input and let the second attempt through.
  8. Letting CLAUDE.md grow forever. Every line is paid on every request. Move procedures into skills once the file passes about 200 lines.

Alternatives and when to use them instead

Hooks, skills and subagents are not the only ways to shape Claude Code, and sometimes a simpler tool is the better fit.

  • Permission rules in settings (allow, deny) are the lightest guardrail. If all you need is “never read .env,” a deny rule does it without a script. Use a hook when the decision depends on the content of the call, not only the tool name.
  • Path-scoped rules in .claude/rules/ load only when Claude works on matching files. They suit directory-specific conventions better than a skill, because they load automatically and need no trigger.
  • Dynamic workflows run many subagents from a script Claude writes and return one result, which suits codebase-wide audits or findings you want cross-checked (Extend Claude Code). Use them when a job outgrows a handful of subagents.
  • Agent teams run several full Claude Code instances that coordinate. They cost the most and are off by default; reach for them only when parallel workers genuinely need to talk to each other. Our comparison of single-agent vs multi-agent architectures helps decide when that is.
  • A workflow tool such as n8n or Make is the better home for automations that do not need an LLM at every step. If a job is “when a form arrives, add a row and send an email,” a deterministic workflow is cheaper and easier to audit than any agent.

The common thread: use the least powerful mechanism that solves the problem. Rules and permissions before hooks, hooks before prompts for anything mandatory, skills before subagents when the output is small, and plain workflows when no reasoning is needed.

Checklist: placing a new behavior

Run any new instruction through these questions in order before you write it down. The first “yes” tells you where it goes.

  • Must it happen every time, with no exceptions? Write a hook. Test the blocking path once with a deliberate violation.
  • Is it only about which tools or files are allowed? Use a permission allow or deny rule first.
  • Does every session need to know it? Add one line to CLAUDE.md. Keep the file under about 200 lines.
  • Does it apply only to certain directories? Use a path-scoped rule in .claude/rules/.
  • Is it a procedure or reference you need sometimes? Write a skill with a description that starts with the trigger. Add disable-model-invocation: true if it has side effects.
  • Would its intermediate output clutter your session? Use a subagent with a tool allowlist and, for bounded work, a cheaper model.
  • Does it talk to an outside system? Connect an MCP server and teach its use in a skill.
  • Do you need it in another repository? Package the set as a plugin.

Review the placement after a week of use. A skill that keeps getting skipped needs a sharper description or should become a hook; a subagent that returns summaries you always expand probably belongs back in the main session. For more on keeping context small as an agent setup grows, read our explainer on agent memory and context management, and for Claude’s wider role in business automation, our overview of Anthropic Claude for enterprise automation.

FAQ

Can a skill start a subagent?

Yes. Add context: fork to the skill’s frontmatter and the skill body runs inside a subagent instead of your conversation. The agent field picks which subagent type runs it, defaulting to the general-purpose agent. A skill can also simply tell Claude to delegate parts of its procedure to named subagents.

Are skills the same as slash commands?

They have merged. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy, and old command files keep working. Skills add a folder for supporting files, automatic loading by description and invocation controls, so Anthropic recommends skills for new work.

Can a hook use AI, or is it always a shell script?

A hook can be a prompt handler that asks a Claude model a single question and returns JSON, or an experimental agent handler that can use tools to verify a condition. These have shorter default timeouts than command hooks. Use them when a check needs judgment, but keep hard guardrails as plain scripts.

Do subagents use the same model as my main session?

By default most inherit the main conversation’s model, but you can set model: haiku, sonnet or opus in a subagent’s frontmatter. Anthropic’s cost guidance suggests a smaller model for simple subagent tasks. An environment variable can also force one model onto every subagent.

Do Agent Skills work outside Claude Code?

The format is published as an open standard at agentskills.io, so a basic SKILL.md with a name and description is portable to other tools that support it. Claude Code-specific fields such as context: fork or hooks are extensions and may be rejected or ignored elsewhere.