On this page

Chapter 1 of 9. Four ways to extend Claude Code, one question that sorts them. Ask who decides whether the thing runs.

Read on 2026-07-14, against Claude Code 2.1.209, the ~/.claude/ directory behind this site holds 31 subagent definitions, 29 skill directories, 23 slash commands, 11 hook scripts and a CLAUDE.md that has grown to 430 lines. A second enforcement layer sits outside it entirely, in a git-hooks repo wired in globally with core.hooksPath. Nobody designed that shape. It accumulated one incident at a time.

The paralysis this chapter is for is the one where you have read the docs, you understand each primitive on its own, and you still cannot say which one your rule belongs in. Choosing wrong is quiet. A rule in the wrong place looks installed and enforces nothing.

Sort the primitives by a single property and most of the confusion drops out. Sort by who decides whether they run.

Who decides that it runs

MechanismFired byRuns in whose contextCan the model skip it?
CLAUDE.mdLoaded at session start, alwaysYoursYes, silently
SkillThe model judging a descriptionYours by defaultYes, silently
Slash commandYou, typing /nameYoursNo, but you have to type it
SubagentThe parent model choosing to delegateIts ownYes, silently
HookThe harness, on a lifecycle eventNot applicableNo

Every row of that table is stated somewhere in Anthropic's own docs. Reading them as one argument rather than four separate pages is what makes them useful.

Skills fire on judgement: "Claude uses skills when relevant, or you can invoke one directly with /skill-name." Subagents fire on judgement too, from the parent model: "Claude uses each subagent's description to decide when to delegate tasks." In both cases the trigger surface is a paragraph of prose, competing for attention against every other paragraph of prose you have written.

CLAUDE.md is blunter than most people expect. Anthropic's memory documentation says that "Claude treats them as context, not enforced configuration," then names the escape route in the very next sentence: "To block an action regardless of what Claude decides, use a PreToolUse hook instead." The docs even explain why. CLAUDE.md "is delivered as a user message after the system prompt, not as part of the system prompt itself."

Hooks are the one mechanism defined by its independence from the model's judgement. They "provide deterministic control over Claude Code's behavior, ensuring certain actions always happen rather than relying on the LLM to choose to run them."

MCP sits outside the table, and people file it in the wrong column constantly. It is a protocol, "an open protocol that enables seamless integration between LLM applications and external data sources and tools." It answers what Claude can reach. What Claude must do is a different question, and it gets its own chapter later.

One version-sensitive note, true as of 2.1.209: commands and skills have merged. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and work the same way. That is why 23 legacy command files in this estate still function. Older tutorials still draw the distinction. Ignore them.

Claude Code subagents vs skills: one question decides it

Ask whether the work needs its own context window and its own price.

If it does, that is a subagent. A subagent "runs in its own context window with a custom system prompt, specific tool access, and independent permissions," and only a text return value crosses back. Anthropic's own trigger for reaching for one is the clearest sentence in the docs: "Use one when a side task would flood your main conversation with search results, logs, or file contents you won't reference again."

If it does not, reach for a skill. By default a skill has no session of its own. It loads into yours and inherits everything you are already paying for. The payoff sits elsewhere: "Unlike CLAUDE.md content, a skill's body loads only when it's used, so long reference material costs almost nothing until you need it."

The gap shows up immediately in frontmatter. Two real agent files from this estate, unedited:

---
name: stuck
description: Use this agent whenever any other agent hits a problem it cannot resolve independently  an ambiguous requirement, a conflict between two valid approaches, a decision with significant cost implications, a security concern, or anything that requires human judgment. Use immediately rather than guessing.
tools: Read
model: haiku
maxTurns: 3
---
---
name: security-auditor
description: Use this agent after implementing authentication, payment flows, file uploads, admin functionality, or any feature that handles user data. Use proactively before any PR that touches auth, data access, or external integrations. Also use when reviewing third-party dependencies.
tools: Read, Bash, Grep, Glob
model: opus
permissionMode: plan
---

Five lines of YAML dial the cost ceiling and the blast radius together. stuck is the escalation path, and it is deliberately the cheapest thing in the system: Haiku, three turns, tools: Read and nothing else. It is structurally incapable of doing the work it was summoned to escalate. security-auditor gets Opus and no write tools at all. Anthropic names that dial as one of the reasons subagents exist, since a subagent lets you "control costs by routing tasks to faster, cheaper models like Haiku."

Now put a skill next to them:

---
name: roadmap
description: Layered living spec per repo  vision, first principles, scaffold, brainstorms, phased plan, decision archive. Tooling to create, query, and grow the roadmap; hooks enforce the discipline at session-start and pre-commit.
---

Two fields, and neither model: nor allowed-tools: is one of them. None of the 29 skills here declares either. Claude Code 2.1.209 would happily accept them: the skills reference lists model, allowed-tools and disallowed-tools as optional frontmatter a skill may set. Nobody in this estate has reached for any of it, so all 29 of them run on the caller's model, inside the caller's permission envelope.

That same reference undercuts the tidy dichotomy above, and it is worth saying so before you build a mental model on it. A skill can set context: fork, which runs it "in isolation" as a subagent with no access to your conversation history. Own context window, which is the exact property I just used to define a subagent. So read the decision as a decision about defaults. Leave context unset and a skill is a procedure applied inside your session; set it and you have written a subagent in a different file format.

With that caveat in hand, the choice reduces to output shape. If what you want back is a summary of noisy work done somewhere else, at a price you chose, delegate to a subagent. If what you want is a procedure applied here, to the files already open in your window, write a skill.

The rule you cannot afford to have skipped

Skills and subagents can both be ignored, silently, with nobody told. Often that costs nothing. Occasionally it is the incident.

The most load-bearing line in this entire system is a comment in CLAUDE.md, written after a session in which the model used a general-purpose agent for an entire auth implementation instead of the specialists the workflow demanded:

# SessionStart hook prints 9-step workflow. Stop hook prints quality checklist.
# Lesson: Agents are voluntary. Hooks are not. Make the non-negotiables hooks.

Anthropic's docs reach the same conclusion in colder language: "If the instruction is something that must run at a specific point, such as before every commit or after each file edit, write it as a hook instead."

Here is what a rule looks like once it has graduated. The gate below blocks any git commit whose staged files span both code and tests without an independent agent having audited them, on the grounds that the agent which wrote both is biased. It tests what it built, not what it might have broken.

def main() -> int:
    if os.environ.get("BBBRAIN_AUDITED") == "1":
        return 0

    try:
        payload = json.load(sys.stdin)
    except Exception:
        return 0  # fail open

    cmd = (payload.get("tool_input") or {}).get("command", "") or ""
    if "BBBRAIN_AUDITED=1" in cmd:
        return 0

Every blocking gate in this estate carries a named bypass. The bypass is always a single env var shaped like BBBRAIN_*=1, and the two commit-message gates log to stderr when one is used. Treat the escape hatch as a design decision rather than a leak. Its rationale is written into the docstring of the gate that requires a roadmap tick:

Fail-open: any unexpected exception returns 0. We don't want a
buggy hook to block legitimate commits — the cost of a missed
tick is recoverable; the cost of an unbypassable hook isn't.

So what is CLAUDE.md actually for?

Facts. Not procedures. Anthropic asks you to "target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence," and the file is loaded in full at every session start regardless of what you happen to be working on.

The one in this estate is 430 lines. Its own version footer still reads Trimmed to ~140 lines. A document that misreports its own size is a document nobody has read end to end in a while, and the docs are precise about what that costs: "if two rules contradict each other, Claude may pick one arbitrarily."

The split follows from that. Stable facts about the project stay in CLAUDE.md. Move a section into a skill once it has grown into a procedure; its body then costs nothing until it loads. And if you can name the incident a rule was written after, it has outgrown prose entirely. Hook it.

The complication, stated honestly

Two of the hooks this constitution quotes most often, including the commit gate above, exist on disk with 41 tests between them and are not registered in ~/.claude/settings.json.

grep -c preflight ~/.claude/settings.json
# 0

They are files without an event. The constitution still describes both as live global PreToolUse hooks. Nothing broke and nothing warned, because the estate has no test for its own wiring. The drift is invisible from inside the document that asserts it.

Read that as the advisory failure mode reappearing one level up. A hook is only deterministic once something registers it, and nothing here checks that anything did.

  1. Write the rule as prose first

    Put it in CLAUDE.md. Most rules never need to leave. If the model follows it, you are finished and you spent nothing.

  2. Watch for the skip

    When it gets skipped, price the skip. Mild friction stays prose. A repeated procedure becomes a skill, and if you cannot afford it firing on a guess, set disable-model-invocation: true and call it by name.

  3. Watch for the incident

    When a skip produces a mess you had to clean up, the rule has earned a hook. Match narrowly, exit 2, give it a named bypass token, and let it fail open on its own errors.

  4. Verify the wiring, not the file

    Type /hooks to see what is actually registered. The browser is read-only. Nothing in it can be aspirational. Compare that list against the directory your scripts live in, and treat every file missing from it as unwired.

The transferable rule

Each primitive is a bet about the model's cooperation. CLAUDE.md and skills both bet that it reads and complies. A subagent raises the stake: it spends a whole context window before you find out. Hooks decline the bet. The non-negotiables end up there for that reason, and every escape hatch gets named after the thing it lets you skip.

The sorting question, then, is never "what kind of thing is this?" Ask what happens when the model ignores it. If the honest answer is "nothing much", prose is fine and prose is cheap. If the honest answer names a specific mess you have already cleaned up once, it belongs in a hook. Then confirm the hook is registered, not merely present.

The expensive bugs in an agentic setup are rarely the ones where something goes wrong. They are the ones where something confidently does not exist. I spent three days chasing that failure across my own homepage, and wrote it up in I built this with Claude Code. The bugs weren't where I expected.. An unregistered hook is that same bug, aimed at the safety net.

The next chapter takes CLAUDE.md apart line by line: what belongs in a constitution, what the 200-line budget actually buys, and why this one is 430 lines and still growing.

// EXERCISE

Audit your estate against the who-decides table

Take your own setup, however small, and put every extension you have written into the chapter's table: each CLAUDE.md rule, skill, command, subagent and hook, tagged with who decides whether it runs. Then find one rule the model has silently skipped at least once and move it up a rung on the graduation ladder, using disable-model-invocation: true if the rung is a skill that must never fire on a guess. Finish by reconciling the hook scripts on your disk against what the /hooks browser reports as registered.

Expected behaviour
  • An inventory where every extension carries a who-decides tag, with no row left as unsure
  • One rule identified from a real transcript or incident where the model skipped it silently
  • That rule re-homed one rung up, with the placement justified by what a skip actually costs
  • A list of every hook script on disk that /hooks does not show as registered, even if that list turns out empty

PROVE IT Reproduce the situation where the rule was originally skipped and capture the new placement firing where the old one stayed silent. A gate you have never seen fire is decoration.

// CHECKPOINT — THE MENTAL MODEL
multiple choice · auto-checked

The chapter sorts CLAUDE.md, skills, subagents and hooks by a single property. Which one?

exact answer · auto-checked

Which skill frontmatter setting runs the skill in isolation, as a subagent with no access to your conversation history?

open · self-checked

Two hooks in this estate exist on disk with 41 tests between them and are described as live in the constitution, yet enforce nothing. Explain why the chapter calls this the advisory failure mode reappearing one level up.

Show answer

A hook is only deterministic once a settings file registers it against an event; until then it is a script sitting on a disk. The constitution asserting those hooks are live is prose that nothing checks, which is exactly the property hooks were built to escape. So the enforcement layer has itself become advisory about its own wiring, and the drift is invisible from inside the document that asserts it.

↺ re-read: “The complication, stated honestly

Lived experience

Sources

  • How Claude remembers your project (CLAUDE.md and auto memory) — Claude Code
    Anthropic (Claude Code official documentation)
    The docs' own statement that CLAUDE.md is context rather than enforced configuration, the user-message delivery mechanism behind that, the 200-line budget, and the explicit instruction to escalate must-run rules to a PreToolUse hook
    code.claude.com
  • Automate actions with hooks (hooks guide) — Claude Code
    Anthropic (Claude Code official documentation)
    The determinism thesis the chapter is built on, and the read-only /hooks browser used to verify which hooks are actually registered rather than merely present on disk
    code.claude.com
  • Hooks reference — Claude Code
    Anthropic (Claude Code official documentation)
    The exit-code contract: exit 2 blocks a tool call and exit 1 is a non-blocking error, the single most misread detail when a policy hook is written
    code.claude.com
  • Create custom subagents — Claude Code
    Anthropic (Claude Code official documentation)
    The context-isolation mechanic, the description-driven (probabilistic) delegation, the frontmatter fields that make model and tools a per-agent dial, and the cost-routing rationale for cheaper models
    code.claude.com
  • Extend Claude with skills — Claude Code
    Anthropic (Claude Code official documentation)
    Skills as probabilistic, description-triggered context that loads only when used; the commands-are-now-skills merge; disable-model-invocation; and the model / allowed-tools / context: fork frontmatter that complicates the skill-versus-subagent line
    code.claude.com
  • Model Context Protocol — Specification (current revision, 2025-11-25)
    Model Context Protocol
    The normative definition of MCP as a connection protocol, used to place it outside the four-way decision table as a question about reach rather than obligation
    modelcontextprotocol.io
Back to guide overview