Over the first five chapters you have installed Claude Code, given it instructions, worked your way out of the places it gets stuck, and designed its permissions. This chapter is about reshaping the tool itself. Learning the names of the extensions will not get you anywhere. What helps is a lookup table: "which one solves the thing that is bothering me right now".

A map for choosing — four questions decide it

There are six extensions, but only four things to think about. Is asking enough / does it have to fire every time / do you want it in a separate context / do you need to reach outside—ask yourself those in that order and the answer usually comes out unique.

Q1
Is asking enough?

If the occasional miss is not fatal, words will do. → CLAUDE.md (the standing premises) / Skills (steps for one particular job)

Q2
Does it have to fire every time?

If a single miss is a problem, stop it mechanically. → hooks. They run when enabled settings match the event and conditions.

Q3
Do you want it in a separate context?

If you do not want a flood of output burying the main thread, run it outside and take back only the conclusion. → subagents

Q4
Do you need to reach outside?

When you need information the AI has no way of knowing (the current values in a database, what is in your issue tracker). → MCP

The fifth question is "are you handing this to other people?"—if you are, plugins. The easy ones to confuse are Q1 and Q2: CLAUDE.md, Skills, and hooks. They all look alike, but they differ in when they get read and who executes them.

CLAUDE.md — separate loading from compliance

CLAUDE.md supplies project context each session when placed in a location that gets loaded. Use ~/.claude/CLAUDE.md for instructions shared across projects. It contains prose instructions, not settings that enforce operation permissions.

If the agent says it read the file but does not follow it, look at these three questions separately.

  • Was it loaded? See whether CLAUDE.md and rules appear under Memory files in /context. The startup location and exclusion settings affect which files are included. Directly loaded AGENTS.md does not appear in this list, so absence alone does not prove it was unread
  • Did it return after compaction? The project-root CLAUDE.md is reloaded from disk and reinserted after /compact. Subdirectory CLAUDE.md files and path-specific rules reload when matching files are read. Decisions kept only in the conversation are handled differently
  • Did it affect the action? Even if it was loaded, check vague rules and conflicting instructions separately. Do not assume that the newest instruction always wins. Specify scope and the conditions for exceptions

The official guideline is fewer than 200 lines per CLAUDE.md file. This is neither a loading cutoff nor a boundary that guarantees compliance. Keep rules needed every time, and separate details with conditions for reading them. Importing everything through @path does not reduce startup context. Use Skills for procedures needed occasionally, and path-specific rules for instructions limited to particular files.

This follows the official memory documentation. For practical ways to tell these apart and differences between tools, see how to investigate AI agents ignoring rules.

“I read it” is not evidence of compliance. Check the loading display separately from diffs and test results. Move mechanically testable conditions into hooks or CI, as discussed next, and report any areas left unverified.

hooks — run checks when conditions match

A written instruction such as “do not rewrite .env” cannot guarantee a compliance rate. If you need to check a condition and block an operation before execution, consider permission settings and hooks.

This section covers command-type hooks, which run shell commands. When enabled settings match the event and conditions, Claude Code itself launches them. You do not need the model to remember to run them. They do not run, however, if they are disabled in settings or the operation takes a path they do not cover. See What Are Claude Code Hooks? for an overview. The following are nine representative events, not a complete list.

SessionStart on start or resume UserPromptSubmit right after you submit [can block] PreToolUse just before a tool = gatekeeper [can block] PostToolUse after a tool succeeds = formatting (cannot undo the completed action) Notification waiting for input or approval Stop end of a response [can block] SubagentStop subagent finished [can block] SessionEnd session ends PreCompact before compaction [can block]

What can be blocked differs by event. Blocking a tool before execution is different from preventing a response from ending so work can continue. Reject dangerous operations at PreToolUse and format automatically at PostToolUse: these are two common starting points. Put the configuration under the "hooks" key in settings.json. The file location determines the scope (~/.claude/ = user, .claude/ = shared, settings.local.json = personal).

Now let’s turn the earlier “do not rewrite .env” into a mechanism. This narrows the official guide’s example of blocking edits to protected files down to .env. You need two things: a setting and a script.

① .claude/settings.json—runs the script just before Edit or Write is called.

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

② .claude/hooks/protect-env.sh—blocks the edit if the target file name starts with .env (including .env.local and similar). On macOS and Linux, make it executable with chmod +x .claude/hooks/protect-env.sh.

#!/bin/bash # .claude/hooks/protect-env.sh command -v jq >/dev/null || { echo "Blocked the edit because jq was not found" >&2; exit 2; } FILE_PATH=$(jq -r '.tool_input.file_path // empty') FILE_PATH="${FILE_PATH//\\//}" # normalize Windows \ to / if [[ "${FILE_PATH##*/}" == .env* ]]; then echo "Blocked: $FILE_PATH is a .env file, so it will not be edited" >&2 exit 2 fi exit 0

The structure is event name → an array of matchers and commands. matcher identifies tool names: "Edit|Write" matches either Edit or Write (omit it to match all tools). The hook receives JSON on standard input, and for Edit and Write, tool_input.file_path holds the absolute path of the file being edited. On Windows, that path uses \ as the separator, so the script converts it to / before comparing. When the hook blocks with exit code 2, the text on standard error goes to Claude as the reason for the denial, and Claude reads it and looks for another approach. 1 is treated as a non-blocking error and the operation continues, so use 2 when you want to block. 0 raises no objection, and normal permission checks follow.

The script uses bash and jq (the official guide’s example also assumes jq). On Windows, hooks run in Git Bash, or in PowerShell when Git Bash is not installed, so this example needs Git Bash. So that a missing jq does not let edits through, the script stops at its very first step in that case.

Hooks can tighten restrictions, never loosen them. Returning an allow only skips the prompt; deny rules always win. A PreToolUse deny still applies in the mode that skips every approval, so it works as a floor under whatever you loosened in Chapter 5.

Test it the same way as the official guide. Ask Claude to “add a one-line comment to .env”: the edit is stopped before it runs, and the Blocked: message goes back to Claude. Also confirm that files other than .env can still be edited as before. If you mistype the script path, you only get a Failed with non-blocking status code notice and the gate stays open, so watch for that notice too. Note that this example stops only the two tools Edit and Write; rewrites through Bash or PowerShell commands take a different path. Widen the scope to match what you want to block. Output formats and differences between events are in the official Hooks guide.

Consider the cost upfront: command hooks automatically run shell commands with your user permissions, and can modify or delete any file your account can access. The official documentation asks you to read and test every command before adding it. Configure only trusted commands and validate their input. Changes you make by editing configuration files directly are normally applied automatically. Check registration through /hooks. If a change has not taken effect, inspect the JSON and file location before restarting the session.

subagents — hand work off in a separate context

Full test output and huge logs can fill context with large amounts of text you only intended to skim, pushing out important premises. Subagents run that work in a separate context and return a summary of the conclusion. They normally have their own context, instructions, and tool permissions, so the parent must explicitly pass the information they need. An execution that forks the conversation and inherits the parent history is an exception; this is different from a skill’s context: fork. Because the report is a summary, ask it to include necessary evidence and unresolved questions as well.

  • Worth splitting off—broad investigation / checks that produce a lot of output / self-contained tasks where only the conclusion matters
  • Not worth splitting off—sequential work / frequent back-and-forth / parallel work touching the same file / fixes that take one or two steps

It is a built-in feature, so it works with no configuration. To add your own definition, put it in .claude/agents/<name>.md (~/.claude/agents/ for all projects) with name / description / tools / model in the YAML front matter. Manage them with /agents, call one with @agent-<name>. Start with the built-in exploration, planning, and general-purpose ones.

description is the key to getting called. The main agent reads it to decide whether to delegate, so a vague description makes automatic selection less likely. Be specific about what it does and when to use it—the same trap is waiting in Skills.

Agent Teams, easily confused with this, is a mechanism where several independent sessions coordinate through a shared task list. It is an experimental opt-in, off by default (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1). Separate instances are running, so it burns a lot of tokens, and it cannot be nested. The difference is compared in Claude Code Subagents vs Agent Teams: Which to Use. When in doubt, a single session or subagents.

Skills — turning procedures into assets

For the "always do it this way" kind of routine, what Skills do better is that they are opened only when needed. Physically it is a folder built around a SKILL.md. Put name and description at the top, the procedure in Markdown below that, and bundle reference/ or scripts/ alongside it. Drop it in .claude/skills/ (per project) or ~/.claude/skills/ (everywhere) and it is picked up.

The core idea is progressive disclosure. Normally, a list of skill names and descriptions enters context, while the body loads through automatic selection or an explicit /skill-name invocation. Supporting materials are read as needed. The description list also consumes context; with many skills, descriptions may be shortened or omitted to fit the budget. Write a specific description, and separately verify that the skill was invoked and that its procedure produced the expected results. See What Are Claude Skills (Agent Skills)? for how to write one.

In one line: CLAUDE.md = premises loaded routinely; Skills = procedures opened through automatic selection or explicit invocation; command-type hooks = processing triggered by configured events and conditions.

MCP — reaching out to systems outside

MCP (Model Context Protocol) is a standard for accessing external data and operations, such as current database values or tickets in an issue tracker. Two common connection methods follow. Diagnose problems by combining the connection method with the error details.

  • Local (stdio)—the server starts as a child process on your computer. The executable path, required environment variables, and the server’s error output are your clues
  • Remote (HTTP)—you connect to a server by URL. The URL, network, server-side errors, and credentials are your clues

Start with the status and details in /mcp. failed can occur with both local and remote servers. If Issue: in claude mcp get <name> includes an HTTP code or error body, read that too. needs authentication is your entry point for revisiting authentication; pending approval, for revisiting approval of a project server. If a fixed Authorization header is rejected with 401/403 during connection, the status is failed even though the problem is authentication. The fixes are collected in Claude Code MCP Connection Error: Causes and Fixes.

Put the shared configuration file .mcp.json at the project root. Use each server’s env for variables passed to a stdio server; use OAuth or headers for HTTP authentication, depending on the service. Do not write actual keys directly into shared files; reference an environment variable such as ${API_KEY} instead. Some variable names, including those for Claude Code’s own credentials, resolve to empty strings in remote URLs and headers; the details are in the official expansion rules.

Tool definitions load on demand by default. In a typical configuration with tool search enabled, only tool names and server descriptions enter context initially. Definitions load upfront when search is disabled, in unsupported environments, or for servers configured with alwaysLoad, among other cases. Output consumes context too, so check actual usage with /context and disable servers you do not use.

plugins — bundling a set and handing it out

Plugins let you bundle skills, subagent definitions, hooks, and MCP configuration for distribution. If you provide a manifest for an individual plugin, put it at .claude-plugin/plugin.json. The standard layout places skills/, agents/, hooks/hooks.json, and .mcp.json at the plugin’s own root. Do not put these under .claude-plugin/. A plugin that uses only the standard layout can omit the manifest.

/plugin marketplace add owner/repo ← register a catalog /plugin install name@marketplace ← install individual ones from it /plugin list ← list plugins installed through marketplaces

These are the basic steps for installing through a marketplace. Registering a catalog alone does not install plugins. /plugin list lists plugins installed through this route, not every plugin available through other routes such as skills directories or sync. The scopes are user (all your projects), project (shared configuration), and local (only you in this project). Even with project scope, each member must install plugins from external sources. Managed scope is administered centrally and restricts users’ configuration changes. Building your own is covered in Claude Code Plugins and Marketplace: Use, Build, Publish.

Plugins can run arbitrary code with your privileges, warns the official documentation. Community listings undergo Anthropic’s automated validation and safety review, but this does not guarantee that they behave as intended. Check the publisher, bundled code, and MCP servers. The permission design from Chapter 5 also applies here to code written by someone else.

What to add first — a word about order

Six of them, laid out—but you do not need all of them. Adding things before you have a problem only buys you configuration complexity. Start from the symptom.

  • Explaining the same thing every time → CLAUDE.md. Skills instead, if it is only for one particular job
  • Written down but ignored → inspect loading, scope, and conflicts. Move mechanically testable conditions into hooks
  • The context fills up fast → push heavy investigation into subagents / disable MCP servers you do not need
  • The AI cannot reach the information → MCP. Connect one at a time, and move on only after you have seen it work
  • You want to hand the same setup around → plugins. Bundle only what already works for you
  • Nothing is bothering you → add nothing. That is the best state to be in

That last line is not a joke. Every extension adds another thing that can go wrong—"Claude Code is acting strange" often turns out to be a layer you added yourself. Which is why the isolation work in Chapter 4 comes first.

Summary

  • The criteria are four questions—is asking enough (CLAUDE.md, Skills) / does it have to fire every time (hooks) / do you want it in a separate context (subagents) / do you need to reach outside (MCP). plugins if you are handing it out
  • CLAUDE.md holds persistent instructions. The root file is reinserted after compaction. Shortening it does not guarantee compliance; check loading and behavior separately
  • Command-type hooks run through Claude Code when configured conditions match. Verify the execution paths and blocking behavior; a hook that runs afterward cannot undo a completed operation
  • subagents work in a separate context and return only a summary. Poor fit for sequential work or frequent back-and-forth
  • Skills use progressive disclosure, opening their bodies when needed. Write specific descriptions for automatic selection, and confirm the procedure’s results even after explicit invocation
  • MCP is a standard for external access. Diagnose problems by combining the status in /mcp with the connection method and error details
  • plugins are the distribution box. Someone else's code runs with your privileges, so check the publisher
  • The order to add them starts from the symptom. One at a time, once the problem exists

Comparing the tools themselves and choosing between them is covered in Chapter 6 of the AI Coding course, "Extending What Claude Code Can Do".

The more you extend, the more it consumes. Last comes the practice of keeping it running over the long haul. Move on to Chapter 7, Cost and Limits.