Key Takeaways
- A skill is text Claude reads in your window. A subagent is a second Claude with its own window. That one difference decides everything else.
- CLAUDE.md, rules, and skills are requests. A hook is a guarantee: it fires on a lifecycle event whether Claude agrees or not, and exit code 2 blocks the action.
- Slash commands are skills now. Plugins aren’t a primitive at all, they’re the box you ship the others in.
- A workflow moves the plan out of Claude’s head and into a script: up to 1,000 agents per run, 16 at a time, one result back.
- Every primitive encodes an assumption about what the model can’t do alone. Re-test that assumption after each model release, and delete what no longer earns its place.
Claude Code now has eight ways to change how it behaves, and most teams use one. In a study of 2,853 public repositories with agent configuration files, 90.6% had a context file like CLAUDE.md, 5.5% had a skill, and 4.6% had a subagent (arXiv, February 2026). Most teams wrote down their conventions and stopped there.
This is the decision table we wish we’d had. One table for all eight primitives, then a head-to-head for each pair people actually search for, with a real file or command under every one. We run all of this on our own codebase, so the examples are real files, not hypotheticals.
The Eight Primitives in One Table
The official docs spread these across six comparison tabs and three pages. Here they are in one place. Read the last column first: it’s the one that tells you what you can actually rely on.
| Who triggers it | Where it runs | What it costs you | What’s guaranteed | |
|---|---|---|---|---|
| CLAUDE.md | Session start, always | Your window | Every request, all session | Nothing. It’s context |
| Rules | Session start, or when a matching file is touched | Your window | Only when matched | Nothing. It’s context |
| Skill | You type /name, or Claude matches the description | Your window (or a fork) | Description always; body on use | Nothing. Claude interprets it |
| Subagent | Claude delegates, or you @-mention it | Its own window | Only the summary comes back | Isolation. Your window stays clean |
| Hook | A lifecycle event fires | Outside Claude entirely | Zero unless it returns output | It runs. Every time |
| Plugin | You install it | Wherever its contents run | The sum of its parts | Same setup in every repo |
| Workflow | You say ultracode or run a saved /name | A script, in the background | Many agents; one result in your window | The script holds the plan, not Claude |
| Agent team | You ask for teammates (experimental) | Separate full sessions | A full context window each | Peers can argue with each other |
Slash commands aren’t a row because they’re skills you invoke by name. More on that below.
For the four rows that perform work, the question that separates them is who holds the plan. In a skill, Claude does, following your text, inside your window. In a subagent, Claude does, turn by turn, in a separate window. In an agent team, a lead session does, across peers. In a workflow, a script does, and Claude only sees the final answer. Hooks are the odd one out: nobody holds a plan. The event fires and your code runs.
Here’s what that looks like on one real job, adding a rate limiter to an API route in a Next.js SaaS. A rule says every route validates input. A skill, /new-api-route, carries the twelve-step procedure. A subagent, code-reviewer, reads the diff in its own window and returns three findings. A hook runs Prettier on every file Claude touched, without asking. Four primitives on one feature, and none of them overlap.
Skills vs Subagents: Context Is the Whole Difference
A skill is text Claude reads. A subagent is a second Claude.
A skill’s description sits in your context every session, capped at 1,536 characters in the docs’ skill listing, and its body loads when it’s used. Everything it does happens in your window, with your history and your tools. A subagent gets its own window, its own system prompt, its own tool list, and often its own model. It does the work and sends back a summary. That’s the whole difference, and it decides everything else: what each one costs, what it can see, and what it can break.
Our code-reviewer is the cleanest example we have, because it’s both at once. The subagent is the reviewer; the skills are its checklists.
docs/ai-context/agents/code-reviewer.md
---
name: code-reviewer
description: Review code for architecture, performance, patterns, and quality.
Use proactively after implementing features or when reviewing changes.
tools: Read, Glob, Grep, Bash
model: opus
skills:
- code-review
- security-reviewer
---
You are a code review specialist. Review all files in the current change set
for architecture compliance, performance issues, pattern violations, and code
quality. Produce a severity-based report.
When Claude hands a 40-file diff to this subagent, the 40 files load into its window. Yours gets six findings back. The two skills it preloads are the same ones you could run yourself with /code-review in the main conversation. Same checklist, different room.
So the rule is short. Use a skill when Claude should know something or follow a procedure: how we write API routes, the release checklist, the naming conventions. Use a subagent when the work produces output you won’t read again (searches, logs, review noise), or when it needs a different model or a narrower tool set than your session has. The documented defaults: 20 subagents running at once, nested up to three layers deep.
Two practitioners, same idea. Simon Willison keeps a standing instruction to “use your judgement to decide an appropriate lower power model and run that in a subagent” for coding tasks: judgment stays on the main loop, the typing gets delegated (Willison, July 2026). Addy Osmani’s version: subagents burn more tokens, “so spend them where a second opinion is worth paying for” (Osmani, June 2026). Both are buying the same thing: a clean window, and a reviewer who isn’t the author.
The bridge between the two is context: fork. Add it to a skill’s frontmatter and the skill’s text becomes the prompt for a subagent instead of loading into your window. One thing that trips people: a forked skill runs in the background by default, so set background: false to wait for its result. The anatomy of a SKILL.md itself, including the trick that injects a live git diff before Claude reads it, is in the loop engineering guide.
Hooks vs Skills: A Request vs a Guarantee
Everything above is a request. Claude reads it and usually complies. A hook is not a request.
The official memory docs say it plainly: Claude treats CLAUDE.md and auto memory “as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead.” Anthropic’s own guide to steering Claude Code draws the line in one sentence: “The model choosing to run a formatter is different from the formatter running automatically” (Anthropic, June 2026).
A hook is an entry in settings.json: an event, a matcher, and a command. The command gets the event as JSON on stdin and answers with an exit code. Exit 0 means no objection. Exit 2 means blocked, and whatever you wrote to stderr goes back to Claude as the reason. Here’s the one we’d put in a SaaS repo first.
Refuse edits to files that should never change in a session (PreToolUse)
#!/bin/bash
# .claude/hooks/protect-files.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
for pattern in ".env" "prisma/migrations/" "terraform/"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
exit 2 # exit 2 = block it; stderr becomes Claude's feedback
fi
done
exit 0 # exit 0 = no objection; the normal permission flow applies {
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
} Secrets, applied migrations, infrastructure. Ask Claude to “add a comment to .env” and the edit is blocked before it happens, with the script’s message handed back so Claude adjusts instead of retrying. The same shape on a PostToolUse event runs Prettier on every file Claude touches.
The gate doesn’t have to live inside the session. A git pre-commit hook or a CI check is a deterministic gate too; the difference is timing. A Claude Code hook stops a bad edit before it exists, a CI gate stops it before it merges, and most teams end up wanting both. Either way the rule is the same: conventions go in CLAUDE.md, guardrails go in hooks.
Hook output lands in context, so hooks and skills pair up naturally: the hook runs the linter, and a /fix-lint skill tells Claude how to resolve what it found.
Slash Commands Are Skills Now
If you learned Claude Code in 2025, you wrote commands as flat Markdown files in .claude/commands/. Those still work, but custom commands have been merged into skills. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and behave the same way.
What the skill form adds is a folder for supporting files and two frontmatter switches that answer the question “who is allowed to fire this?”
---
name: deploy
description: Deploy the current branch to Cloud Run after the release checklist passes.
disable-model-invocation: true # only you can run /deploy; Claude never auto-invokes it
--- disable-model-invocation: true is for anything with side effects: deploys, releases, database migrations. Claude can’t reach for it on its own, and it costs zero context until you type it. The mirror switch, user-invocable: false, hides a skill from the / menu so only Claude can load it, right for reference material you’d never invoke by hand. The built-in commands you already use, like /loop and /goal, are the same mechanism shipped by Anthropic.
Plugins Are Packaging, Not a Primitive
A plugin doesn’t do anything by itself. It’s a folder with a manifest at .claude-plugin/plugin.json and any mix of skills/, agents/, hooks/hooks.json, and an .mcp.json, plus newer slots for LSP servers, background monitors, and saved workflows. Install it and every part inside becomes available, with skills namespaced as /plugin-name:skill so two plugins can both ship a /review.
The trigger for building one is specific: a second repository needs the same setup. Until then, keep everything standalone in .claude/. When the day comes, claude plugin init my-kit scaffolds the manifest, and claude --plugin-dir ./my-kit loads it for testing without installing.
We don’t ship VibeReady as a plugin, and the reason says something about where plugins stop. A plugin distributes to Claude Code. Our kit has to work in Cursor and Windsurf too, so make ai-setup does the plugin’s job across tools: it copies the 14 master rules into .claude/rules/, .cursor/rules/*.mdc, and .windsurf/rules/, each in that tool’s frontmatter dialect, and symlinks CLAUDE.md to AGENTS.md so all of them read one core file. That’s the same “same setup, every repo” promise, one layer up. Where the instruction files themselves should live is its own decision.
Workflows vs Subagents: One Helper, or a Script That Runs Many
A subagent is one helper you send off. A workflow is a script that sends off many helpers and hands you one answer. Claude writes the script for the task you describe, you approve it, and it runs in the background while you keep working. Nothing in between lands in your window.
Workflows shipped on May 28, 2026, in v2.1.154, the same day as Opus 4.8. You start one by putting ultracode in your prompt (the trigger word was workflow until a June 1 rename) or by asking for a workflow in plain words (Claude Code changelog). Two numbers to keep in mind: a run can use up to 1,000 agents, but only 16 run at once. “Hundreds of parallel agents” means hundreds per run, not at the same time.
Here’s one on a problem every multi-tenant SaaS has: making sure no API route forgets to scope its queries by organization.
> ultracode: audit every route handler under src/app/api for Prisma queries that
skip organizationId scoping, and adversarially verify each finding
.claude/workflows/audit-org-scoping.js (saved from /workflows with s)
export const meta = {
name: 'audit-org-scoping',
description: 'Find API routes that skip organizationId scoping, then verify each finding',
}
const found = await agent('List every route.ts under src/app/api/.', {
schema: { type: 'object', required: ['files'],
properties: { files: { type: 'array', items: { type: 'string' } } } },
})
const findings = await pipeline(found.files, file =>
agent(`Check ${file}: is every Prisma query scoped by organizationId? Report violations.`, { label: file }),
)
const verified = await pipeline(findings.filter(Boolean), f =>
agent(`Adversarially verify this finding. Return null if it does not hold: ${JSON.stringify(f)}`, { label: 'verify' }),
)
return verified.filter(Boolean) Read it top to bottom. One agent lists the routes. One agent per route checks it. One agent per finding tries to knock it down. You get the findings that survived, and next quarter the same script runs again as /audit-org-scoping. That last step, a second agent checking the first, is what a plain subagent fan-out doesn’t give you. It’s the same idea as the separate judge in our eval suite.
One limit to know before your first run: a workflow can’t stop to ask you anything. If you want to sign off between stages, run two workflows. And try it on one directory first, because a run can burn far more tokens than doing the task in conversation.
The biggest public example is Bun’s rewrite from Zig to Rust: about a million lines in 11 days, roughly 50 workflows, about $165,000 at API pricing, and 19 known regressions, with Bun disclosing that Anthropic had acquired it and that the work used a pre-release model (Bun, July 2026). Zig’s creator, Andrew Kelley, called the output “[a] million lines of unreviewed slop” (The Register, July 2026). Both facts hold. A workflow can write a million lines. Reviewing them is still your job.
The rule: a focused side task is a subagent. A job too big for a few of them, or one where you want the findings checked before you see them, or one you’ll run again, is a workflow.
Subagents vs Agent Teams
A subagent works inside your session and reports back to it. An agent team is several full Claude Code sessions with a shared task list that message each other directly. Teams are experimental, off by default, and switched on with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. Each teammate costs a full context window, so the docs say start with three to five. Use one when the workers need to argue: five teammates trying to disprove each other’s theory about a bug is a team job. A review from three angles that only needs to report back is still subagents.
Which Primitive When: The Trigger Table for a SaaS Codebase
Don’t pick from the feature list. Pick from the symptom. Each primitive has a moment where it becomes obvious, and here they are with the version we hit building a multi-tenant Next.js product.
| The symptom | In practice | |
|---|---|---|
| Rule | Claude forgot the same convention twice | “Every Prisma query is scoped by organizationId” went into the database rule, matched to the data layer, instead of being repeated in chat |
| Skill | You pasted the same procedure a third time | The PR checklist became /pr-create; the migration steps became /db-migrate |
| Subagent | A side task flooded your window with output | Review moved into code-reviewer; QA moved into qa-tester. The main window sees findings, not files |
| Hook | Something must happen every time, no judgment needed | Formatting on every edit; a block on .env, applied migrations, and Terraform |
| Plugin | A second repo needs the same setup | For Claude Code alone, a plugin. For Cursor and Windsurf too, a script that copies the rules into each tool’s folder |
| Workflow | The job is bigger than a few agents, or you want findings verified | Auditing every route handler for scoping, with a verification pass |
| Agent team | The workers need to argue with each other | Competing hypotheses on a flaky-connection bug. Rare, and experimental |
The same table tells you when to update what you have. A repeated review comment is a rule edit, not another chat correction. A skill you keep tweaking by hand needs another revision. And a rule Claude follows fine without the rule is a rule to delete.
What a Working Setup Looks Like
Most repos need three of the eight, arranged so each one carries a different kind of knowledge. Rules hold conventions, one topic per file, scoped to the paths they describe. Skills hold procedures, named after the verb. Subagents wrap a skill or two in a narrower tool list and their own window. A hook or two guards the few things that must never happen. That’s the whole setup, and it fits in four places.
.claude/
├── rules/database.md # "every query is scoped by organizationId"; loads with the data layer
├── skills/new-api-route/SKILL.md # the twelve-step procedure, run as /new-api-route
├── agents/code-reviewer.md # preloads code-review + security-reviewer; read-only tools; own window
└── settings.json # the protect-files hook from above
The order you add them matters less than keeping each thing in its lane. A convention that ends up in a skill gets skipped whenever the skill isn’t invoked. A procedure that ends up in CLAUDE.md costs context on every request. A guardrail that lives anywhere but a hook is a suggestion. This is the arrangement we ship in VibeReady, and it works the same whether you write it yourself or start from a kit; rules and skills carry over to Cursor and Windsurf, subagents are Claude Code only.
If you’d rather start from a working set of rules, skills, and review subagents already wired to a production Next.js codebase, that’s the VibeReady AI Framework. See editions from $99 →
Remove What the Model No Longer Needs
Every rule, skill, and subagent you add is a patch for something the model couldn’t do reliably at the time. Models improve. A setup that only ever grows ends up carrying patches for problems that are gone: a rule that costs context on every request to prevent a mistake the model stopped making, or a review subagent that costs tokens to catch what the model now gets right the first time.
Anthropic’s own harness team hit this at scale. Their setup added a second agent to judge the first one’s work, because agents asked to grade themselves “tend to respond by confidently praising the work.” It helped, but the full arrangement cost over twenty times a solo run, $200 against $9, and only paid off on tasks the model couldn’t do alone. When Opus 4.6 arrived, they deleted an entire component the new model no longer needed (Anthropic Engineering, March 2026).
The practical version is simple. After each model release, pick one rule or skill and turn it off for a week. If nothing regresses, delete it. Your harness should get smaller as the model gets better, and the only way to know whether yours does is to test it.
Official docs for each primitive
Skills · Subagents · Hooks reference · Plugins · Dynamic workflows · Agent teams · CLAUDE.md and rules · Extend Claude Code (the official comparison)
Frequently Asked Questions
What is the difference between a Claude Code skill and a subagent?
A skill is text Claude loads into your current conversation: a checklist, a procedure, reference material. A subagent is a separate Claude with its own context window, tools, and model that does work and sends back a summary. Use a skill when Claude should know something; use a subagent when the work would flood your window with output you won't read again.
Do I need hooks if I already have rules in CLAUDE.md?
Yes, for anything that must hold every time. CLAUDE.md and rules are context, and Claude usually follows them. A hook is enforcement: it runs at a lifecycle event whether or not Claude agrees, and a PreToolUse hook that exits 2 blocks the action outright. Put conventions in CLAUDE.md and guardrails in hooks.
Are slash commands the same as skills in Claude Code?
Yes. Custom commands were merged into skills. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and behave the same way. Skills add a folder for supporting files and frontmatter switches that control whether you, Claude, or both can invoke them.
What is the difference between a plugin and a skill?
A skill is one unit of instructions. A plugin is a package that bundles skills, subagents, hooks, and MCP servers so they can be installed together in another repo or shared through a marketplace. Plugin skills are namespaced, like /my-plugin:review. Start standalone in .claude/ and convert to a plugin when a second repository needs the same setup.
When should I use a dynamic workflow instead of subagents?
When the job outgrows a handful of subagents, or when you want findings cross-checked before you see them. A workflow is a script Claude writes that runs up to 1,000 agents per run, 16 at a time, and returns one result. Reach for it for codebase-wide audits, large migrations, and research; a single focused side task is still a subagent.
Are agent teams the same as subagents?
No. Subagents run inside your session and report back to it. Agent teams are separate full Claude Code sessions that share a task list and message each other directly. Teams are experimental, need CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1, and cost more tokens, so use them only when teammates need to challenge each other's findings.
Have more questions? See our full FAQ →