Architecture Skills vs MCP vs mods vs everything else
Which extension point?
Claude Code has about ten ways to change how it behaves. They overlap, and the names don't make the difference obvious. The short version: text that teaches Claude goes in CLAUDE.md or a skill, new abilities come from MCP, a separate worker is a subagent, a script on an event is a settings hook, and code inside the loop is a mod. A plugin is the box they ship in.
The whole map in one table
| Extension point | What it is | Who decides it runs | What it can change | Context cost |
|---|---|---|---|---|
CLAUDE.md (and AGENTS.md) | Markdown instructions loaded into every conversation | Always on | What Claude knows and tends to do. Advisory: Claude can still choose otherwise. | Every request |
| Skill | A folder with SKILL.md, plus optional scripts and references | Claude, from the description, or you by name | What Claude knows and does for one kind of task | The description always; the body when used |
| Custom slash command | A Markdown prompt you invoke as /name | You | The prompt Claude receives. It still starts a Claude turn. | When invoked |
| Subagent | An agent definition (agents/*.md) with its own prompt, tools and model | Claude delegates, or you ask | Who does a piece of work, in a fresh context | Its own context; the result comes back as text |
| Output style | A system-prompt variant for tone and format | You pick it | How Claude writes | Every request |
| MCP server | An external process or service that offers tools, resources and prompts | Claude calls its tools | Which tools Claude has: databases, APIs, browsers | Tool names; schemas load through tool search |
| Permission rules | allow, ask and deny patterns in settings | Every tool call | Whether a call runs, asks or is refused. Declarative, so it can't inspect content beyond the pattern. | None |
| Settings hook ("classic") | A shell command, HTTP call, prompt, agent or MCP tool run on a lifecycle event, JSON in and out | The event | Block, allow or annotate a tool call or prompt. Rewrite a call's input or result. Add context. | Only what it adds |
| Status line | A script whose output is shown under the prompt | Each redraw | One line of the screen | None |
| Mod | TS or JS functions running inside Claude Code, chained on 46 engine events | The event | Tool calls, prompts, the system prompt, model requests, subagents, commands, compaction, stored rows, and what the interface draws | None unless it adds text |
| Plugin | A package of any of the above, installed from a marketplace | You install it | Whatever it carries | The sum of its parts |
Two more sit outside the box: the Agent SDK, for running Claude Code inside your own program, and managed settings, which an organization uses to decide which of all the above may load.
Mods next to their neighbours
The four most often confused are mods, settings hooks, skills and MCP servers. This expands the official comparison:
| Mod | Settings hook | Skill | MCP server | |
|---|---|---|---|---|
| Runs | In Claude Code's process (a worker thread), loaded once, keeps state | Spawned per event: shell, HTTP, prompt, agent or MCP tool | Not at all. Claude reads it. | A separate process or remote service |
| Several at once | A sequential, ordered chain. Each one sees what the one before passed on. | Run in parallel. The most restrictive decision wins. Input rewrites are last-writer-wins. | Claude picks | All tools available |
| Can draw | Panes, a band, restyled rows, spinner, dialogs | No | No | No |
| Adds commands | Yes: code that runs with no Claude turn, even mid-turn | No | Yes: a prompt that starts a turn | MCP prompts appear as commands |
| Adds tools | Yes ($.tool.register), served by its own hook | No | No (it can tell Claude to run scripts) | Yes, that's the point |
| Can fail open | Yes: a hook that throws or overruns is skipped unless it has .catch | Depends on exit code and config | n/a | A failed tool is an error result |
| Language | TypeScript or JavaScript | Anything that reads stdin | Markdown | Anything |
| Reviewable before install | claude plugin validate lists hooks and calls | Read the script | Read the Markdown | Read the server |
One job, five ways: "never run rm -rf"
The clearest way to feel the differences is to try the same job with each one and ask what it actually guarantees.
| Approach | What it looks like | What it guarantees |
|---|---|---|
| CLAUDE.md | "Never run rm -rf; ask me instead." | Nothing. It's advice. Claude usually follows it, and a long session or an odd prompt can drift. |
| Skill | A "safe cleanup" skill that explains alternatives | Nothing, and it only loads when the task looks like cleanup. The wrong tool for a prohibition. |
| Permission rule | "deny": ["Bash(rm -rf:*)"] | That pattern is refused. It's declarative and fast, and it misses rm -fr, rm -r -f and find … -delete. |
| Settings hook | A PreToolUse script that parses the command and exits with a block | Whatever your script checks, in any language. It runs in parallel with other hooks and can't show UI. A managed one runs before any mod. |
| Mod | A tool.call guard with .catch, or one that holds the call and asks with $.ui.ask | Whatever your code checks, in a known order, with UI. It fails open without .catch. A worker crash loop unloads it. |
In practice: the deny rule for the obvious spelling, a hook or mod for the rest, and a CLAUDE.md line so Claude doesn't try in the first place. Layers, not a winner.
Pick one
Rules of thumb
- Start with text. If you keep pasting the same instructions, write a CLAUDE.md line (always relevant) or a skill (relevant to one kind of task). It's cheap, readable and easy to change.
- Need a new ability? MCP. If Claude must reach a system it can't reach today, that's a tool, and tools come from MCP servers. A mod can register a tool too, which is handy when the tool needs session state the mod already has.
- Need isolation? A subagent. A separate context for a big search or a review, possibly on a cheaper model. A mod can pin which model a subagent uses (
agent.spawn) or hide an agent type (agent.offer). - Need a guarantee? Rules first, then hooks or mods. Permission rules for patterns. A settings hook if you already have the script, or if you need it to run before any mod (managed). A mod if you need order, state, UI or to rewrite the event.
- Need to draw, or to run code on a command with no Claude turn? Only a mod can.
- Shipping several? A plugin. One install can bring a skill, an MCP server, a subagent and a mod that work together.
Where a decision model fits
Our sister site, Decision Tier, studies decision models: fast, typed judgments such as "is this command destructive?" with a probability attached. A decision model is a callee, not an extension point. In Decision Tier's words, mods and hooks call decision models; skills and CLAUDE.md teach Claude when to trust them.
- From a mod or settings hook: a
$.http.fetchin a guard, with a timeout and.catchfailing closed. This is the hot path. See Mods meet the cascade. - As an MCP tool: only when you want Claude to choose to ask for a judgment. That's rarely what you want, because then the expensive tier decides when to consult the cheap one.
- Never as a skill or subagent. A skill is instructions, not a judge, and a subagent is another LLM.