I’ve been using Claude Code for months, and I STILL had to look up the difference between a Skill and a Plugin last week.
Not because I’m forgetful. But because the Claude Code ecosystem has grown fast, and the naming can be confusing. “Commands” became a legacy concept. “Skills” absorbed them. “Agents” are sub-workers, not the AI itself. And “Plugins” bundle everything together into one installable package.
By the end of this post, you’ll never mix them up again. I’ll give you the mental model, real code examples, and five different analogies for each component — because one analogy never sticks for everyone, but five will.
Here’s the full map of what we’re covering:
Claude Code Components├── CLAUDE.md ← Project memory (6 levels!)├── Skills ← Expert knowledge modules├── Commands ← Slash triggers (legacy, now part of Skills)├── Hooks ← Auto-triggers on events├── Agents ← Sub-workers (spawned, not main Claude)└── Plugins ← Distributable bundles of all the aboveThe Complete Component Map
Before diving in, here’s where everything lives on disk:
your-project/├── .claude/│ ├── CLAUDE.md ← Project memory (alternative location)│ ├── settings.json ← Config + hooks + permissions│ ├── settings.local.json← Local overrides (gitignored)│ ├── skills/ ← Expert knowledge modules│ │ └── code-review/│ │ └── SKILL.md│ ├── commands/ ← Slash triggers (legacy)│ │ └── deploy.md│ ├── agents/ ← Sub-workers│ │ └── researcher.md│ └── rules/ ← Modular rules (loaded on-demand)│ └── testing.md├── CLAUDE.md ← Project root memory (main location)├── CLAUDE.local.md ← Local-only memory (gitignored)└── .gitignoreSeven things. Each has a specific job. Let’s go through them one by one.
Component 1: CLAUDE.md — Project Memory
What It Is
A Markdown file Claude reads at session start — every single session, automatically. It’s your permanent instruction set that persists across conversations so you don’t have to re-explain your project conventions each time.
Real Code
## Project: Payments APIREST API for processing payments. Handles Stripe, PayPal, and bank transfers.
## Tech Stack- Node.js + TypeScript + Fastify- Prisma + PostgreSQL- Zod for validation
## ArchitectureHandler → Service → Repository → Database
## Conventions- All async/await (no .then() chains)- kebab-case for files, PascalCase for classes- Service layer handles all business logic (never in handlers)
## Rules**NEVER:**- Commit .env files- Put business logic in route handlers- Access process.env outside config/index.tsThe 6 Levels You Probably Don’t Know About
Here’s the part most people miss: CLAUDE.md isn’t just one file. There are six levels of memory, loaded in order, more specific overrides broader:
| Level | Location | Scope |
|---|---|---|
| 1. Managed policy | /Library/Application Support/ClaudeCode/CLAUDE.md | Organization-wide |
| 2. User memory | ~/.claude/CLAUDE.md | All your projects |
| 3. Project memory | ./CLAUDE.md or ./.claude/CLAUDE.md | Team (checked into git) |
| 4. Project local | ./CLAUDE.local.md | Just you (gitignored) |
| 5. Project rules | ./.claude/rules/*.md | Modular, scoped by path |
| 6. Auto memory | ~/.claude/projects/<project>/memory/ | Per-project AI notes |
A couple of non-obvious behaviors worth knowing:
- Child directory CLAUDE.md files load on-demand, not at startup
- You can import other files with
@path/to/file.mdsyntax (max depth 5 — don’t go deeper) - Rules in
.claude/rules/let you split CLAUDE.md into focused modules (e.g.,testing.md,api-conventions.md)
5 Analogies
- Soldier: The mission briefing that every soldier reads before deployment. Once written by command, relied upon by everyone.
- Romance: Your partner’s love language manual — written once, prevents 90% of misunderstandings. Nobody wants to re-explain “no, I don’t like surprises” every morning.
- RPG: Your character’s backstory and class abilities. The dungeon master reads it before every session so you don’t have to re-introduce yourself.
- Corporate: The company handbook that HR gives new employees. Everything in one place so nobody has to explain the same rules 40 times.
- Gen Z: Your “about me” pinned post. First thing anyone sees. Sets expectations. No DMs asking basic questions.
When to Use It
Always. Every project. Within the first 10 minutes of starting a new codebase. Write it once, stop repeating yourself forever.
Common Mistakes
- Writing documentation prose instead of directives. CLAUDE.md says “do this”, README.md says “here’s what this is”
- Being too generic (“use TypeScript” doesn’t help — “use strict mode, no
any, all functions typed” does) - Not including a
## Rules / NEVERsection — that section alone saves hours of cleanup
Component 2: Skills — Expert Knowledge Modules
What It Is
A directory (not a single file) containing a SKILL.md that defines an expert persona, what tools it can use, and how it behaves. When invoked, Claude takes on that skill’s persona and constraints.
Skills are the modern, recommended way to do everything that used to be done with standalone commands. If you’re reading old docs that only mention “commands”, know that skills are the current path.
Real Code
Directory structure:
.claude/skills/code-review/SKILL.md---name: "code-review"description: "Thorough code review with security and performance focus"user-invocable: trueallowed-tools: ["Read", "Glob", "Grep", "Bash"]model: "sonnet"---# Code Review Skill
You are a senior engineer specializing in security-focused code review.
When invoked, you:1. Read the changed files in the current diff2. Check for security vulnerabilities (SQL injection, XSS, auth bypasses)3. Check for performance issues (N+1 queries, missing indexes, unnecessary loops)4. Check for adherence to project patterns (read CLAUDE.md first)5. Output a structured review: CRITICAL > HIGH > MEDIUM > LOW
Always provide specific line numbers and suggest concrete fixes.Once created, users invoke it as /code-review. If placed in ~/.claude/skills/, it’s available across all your projects.
The YAML frontmatter controls behavior:
allowed-tools— limits what Claude can do when this skill is activemodel— can specify a different model for cost optimizationuser-invocable: true— makes it appear as a slash command
5 Analogies
- Soldier: Sniper school training — specialized knowledge that makes you deadly effective at one specific thing, which nobody else can do as well.
- Romance: That one thing they learned just for you. Your partner learned to cook your favorite Vietnamese dish, watches football with you even though they hate sports. Specialized effort for a specific person.
- RPG: Passive skill equipped to your character. “Code Review Mastery” gives +25% to finding bugs and a special “Security Scan” ability.
- Corporate: The security team specialist on loan to your project. They have expertise and access that generalists don’t have.
- Gen Z: That thing you’re cracked at. Not everything, just that one thing. Everyone calls you for it. “Yo, can you review my PR? You’re GOATED at this.”
When to Use It
When you have a repeatable task that needs specific expertise or tool constraints. Code review, deployment checks, documentation generation, performance profiling — anything you do more than twice is a skill candidate.
Common Mistakes
- Creating a flat
.mdfile instead of a directory withSKILL.mdinside - Forgetting
user-invocable: truethen wondering why/skill-namedoesn’t work - Over-restricting
allowed-tools— if the skill needs to run shell commands to verify its findings, give itBash
Component 3: Commands — Slash Triggers (Legacy)
What It Is
A .md file in .claude/commands/ that gets triggered when you type /filename. Simple, flat, no YAML frontmatter. Just instructions with an optional $ARGUMENTS placeholder for input.
Important: Commands are now considered legacy. The official recommendation is to use Skills instead. But .claude/commands/ still works, and you’ll see it in older setups, so it’s worth understanding.
Real Code
File: .claude/commands/commit.md
Review the staged git diff and write a conventional commit message.
Steps:1. Run: git diff --staged2. Analyze what changed and why3. Write a commit message following: <type>(<scope>): <description> Types: feat, fix, docs, style, refactor, test, chore4. Run: git commit -m "<message>"
Additional context: $ARGUMENTSInvoke with /commit or /commit fix the auth timeout issue.
5 Analogies
- Soldier: Radio call signs. “Alpha-6, do you copy?” — one phrase triggers a specific, well-understood protocol.
- Romance: Pet names that trigger specific actions. Say “I’m tired” and they automatically put on your comfort show and order your favorite food. No explanation needed.
- RPG: Hotkey bindings. Press F5 to quicksave. Press Q to drink a health potion. One keystroke, pre-defined action.
- Corporate: Speed dial on the office phone. Press 3 for Legal, press 7 for IT support. Everyone knows what each number does.
- Gen Z: “Say less.” The whole shortcut. No explanation required. Just say it and the other person already knows exactly what’s happening.
When to Use It
Honestly, if you’re starting fresh today, just use Skills. Use Commands only when you’re maintaining an existing setup that already uses them, or if you want something truly minimal with zero YAML overhead.
Common Mistakes
- Creating new commands in 2025 — migrate to Skills for all new work
- Not knowing about
$ARGUMENTS— you can pass context to commands just like function arguments
Component 4: Hooks — Auto-Triggers
What It Is
Scripts that run automatically when specific events happen in a Claude Code session. Configured in .claude/settings.json. No prompting required — they fire based on events.
There are 17 hook events (not just the 4 you’ll see in most tutorials). The key ones:
| Event | When It Fires | Use Case |
|---|---|---|
PreToolUse | Before any tool call | Block dangerous commands |
PostToolUse | After a tool succeeds | Auto-lint, run tests |
Stop | When Claude finishes a turn | Summarize changes |
SessionStart | Session begins | Load context, log session |
UserPromptSubmit | User sends a message | Validate prompt format |
Notification | Claude sends notification | Custom alerting |
SubagentStart | Subagent spawns | Log agent lifecycle |
SubagentStop | Subagent completes | Collect agent output |
There are also 3 handler types (not just shell scripts):
command— shell script, the classic approachprompt— AI evaluates the situation and decidesagent— spawns a subagent as a verifier
Real Code
.claude/settings.json:
{ "hooks": { "PreToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "bash .claude/hooks/block-dangerous.sh" }] }], "PostToolUse": [{ "matcher": "Edit", "hooks": [{ "type": "command", "command": ".claude/hooks/auto-lint.sh" }] }], "Stop": [{ "matcher": "", "hooks": [{ "type": "command", "command": ".claude/hooks/log-session.sh" }] }] }}The hook script receives a JSON payload on stdin:
#!/bin/bashinput=$(cat)command=$(echo "$input" | jq -r '.tool_input.command // ""')
if echo "$command" | grep -qE '\brm\s+-rf'; then echo '{"error": "BLOCKED: rm -rf is not allowed."}' >&2 exit 2 # exit 2 = block the actionfi
exit 0 # exit 0 = allow itExit codes matter:
exit 0— success, proceedexit 2— block the action (with your error message)- Any other non-zero — error, but don’t block
5 Analogies
- Soldier: Tripwires and booby traps. You don’t stand guard 24/7 — you set up automatic triggers that fire when something specific happens.
- Romance: Automatic habits born from caring. You always kiss goodbye before leaving without thinking. She automatically turns off your gaming PC when she sees you fell asleep. Pure reflex, no decision needed.
- RPG: Passive abilities that auto-trigger on condition. “When HP drops below 30%, automatically use a health potion.” You didn’t press anything — the game handled it.
- Corporate: Automated approval workflows. “When a document is submitted, automatically notify the legal team.” Nobody pressed a button. It just… happened.
- Gen Z: Auto-reply and read receipts. “Seen 9:47 PM.” You didn’t actively respond, but something happened automatically the moment a condition was met.
When to Use It
Whenever you want something to happen reliably without being prompted. Auto-lint after edits, block dangerous commands before they run, log all AI actions for audit purposes, run tests when source files change.
Common Mistakes
- Slow PreToolUse hooks — they run synchronously and block Claude while running. Keep them under 500ms.
- Forgetting to
chmod +xyour hook scripts - Not handling missing JSON fields — always use
jq -r '.field // ""'with a default value
Component 5: Agents — Sub-Workers
What It Is
Markdown files in .claude/agents/ that define specialized sub-workers. When Claude (or you, via the Task tool) spawns an agent, it runs as a separate context with its own rules, tool access, and model settings.
Key distinction: only the main Claude thread can spawn agents. Agents cannot spawn other agents. The main thread is the orchestrator.
Project-level agents (.claude/agents/) take priority over user-level agents (~/.claude/agents/).
Real Code
.claude/agents/researcher.md:
---description: "Research specialist for finding documentation and external references"tools: ["Read", "Glob", "Grep", "WebSearch", "WebFetch"]model: "sonnet"permissionMode: "acceptEdits"maxTurns: 20---# Research Agent
You are a research specialist. Your job is to find accurate, up-to-date information from external sources.
When given a research task:1. Search for official documentation first2. Find 2-3 reliable sources3. Summarize findings with source URLs4. Flag anything that looks outdated or contradictory
You do NOT write code. You do NOT make changes to files.You research and report. That's it.The main thread spawns this agent via:
Task(subagent_type="researcher", prompt="Find the latest Stripe webhook documentation")The YAML frontmatter controls:
tools— what tools the agent can use (limits its blast radius)model— can use a cheaper model for cost optimizationpermissionMode— how it handles permission promptsmaxTurns— prevents runaway agents
5 Analogies
- Soldier: Squad members with different specialties. You’re the squad leader. You send the sniper to the rooftop, the medic to the casualty, the breacher to the door. Each person has one job and stays in their lane.
- Romance: Your wingman or wingwoman. You’re at the event. They handle the research (“I heard she likes hiking”), you handle the conversation. Different roles, same mission.
- RPG: Party members. You’re the main character. The healer handles HP, the tank handles aggro, the DPS handles damage. You can’t do everything yourself — that’s what the party is for.
- Corporate: Department specialists on loan. Legal reviews the contract, Finance models the revenue, Engineering scopes the work. The project manager (you) coordinates. Specialists execute.
- Gen Z: Group chat roles. Every friend group has them: the planner, the hype person, the one who finds the best restaurant, the one who books the Airbnb. Nobody does everything. Everyone has their thing.
When to Use It
When you have a task that benefits from specialization or isolation. Research tasks that need WebSearch. Code review agents with read-only tool access. Test runners that shouldn’t touch source files. Long-running parallel work.
Common Mistakes
- Giving agents too many tools — restrict
toolsto only what’s needed for the job - Forgetting that agents can’t spawn sub-agents (only the main thread can)
- Setting
maxTurnstoo high — give each agent enough turns to complete its task, not unlimited
Component 6: Plugins — Installable Packages
What It Is
A distributable bundle that packages all the other components together. One plugin can contain skills, commands, agents, hooks, MCP servers, LSP servers, and default settings — everything needed to extend Claude Code for a specific use case.
You install a plugin once and get all of its capabilities. Skills get namespaced to prevent conflicts.
Structure
my-plugin/├── .claude-plugin/│ └── plugin.json ← manifest (name, version, description)├── skills/ ← knowledge modules│ └── deploy/│ └── SKILL.md├── commands/ ← slash commands (legacy)│ └── rollback.md├── agents/ ← subagent definitions│ └── deploy-verifier.md├── hooks/│ └── hooks.json ← event handlers├── .mcp.json ← MCP server configs├── .lsp.json ← LSP server configs└── settings.json ← default settingsplugin.json manifest:
{ "name": "my-deploy-plugin", "version": "1.2.0", "description": "Deployment tools for AWS + Vercel projects", "author": "Your Name"}Install with:
claude plugin install my-deploy-plugin# or from a local directory:claude --plugin-dir ./my-pluginAfter installation, skills are namespaced: /my-deploy-plugin:deploy instead of just /deploy. This prevents naming conflicts when you have multiple plugins installed.
5 Analogies
- Soldier: The complete mission kit with everything pre-loaded. One case arrives — it has the weapons, the comms gear, the maps, the vehicle keys, the mission brief. Everything in one package, nothing to source separately.
- Romance: The complete date package someone already planned. Restaurant reservation, flowers at the door, playlist queued up, backup plan if it rains. You didn’t have to think about any of it. It just works.
- RPG: The DLC expansion pack. You buy “Desert Warrior DLC” and immediately have: 3 new weapons, 2 new passive skills, 1 new party member, access to the desert map, and 5 new side quests. One purchase, everything included.
- Corporate: Enterprise software suite. You buy “Salesforce” and get CRM, email integration, reporting, mobile app, and API access. Not just one tool — a whole ecosystem. Configured and ready.
- Gen Z: That app that just works from the App Store. Download, sign in, it’s all there. Settings, themes, integrations, the whole thing. No manual setup. No “now also download this other app and connect them.”
When to Use It
When you want to share your Claude Code setup with others, when you want to publish a reusable toolset for a specific framework or workflow, or when you’ve accumulated enough skills/agents/hooks that packaging them as a unit makes sense.
Common Mistakes
- Building a plugin when you just need a skill — plugins are for distribution, not everyday use
- Forgetting the namespace prefix after installation (
/deploybecomes/plugin-name:deploy) - Not specifying
allowed-toolsin skill frontmatter inside a plugin — plugins you distribute may run in environments you don’t control
Component 7: Permissions & File Access
What It Is
The system that controls what files Claude Code can read and write. This is often confused with a fictional .claudeignore file — .claudeignore is NOT an official Claude Code feature. It doesn’t exist.
Instead, use permissions.deny in .claude/settings.json:
{ "permissions": { "deny": [ "Read(.env)", "Read(.env.*)", "Read(secrets/**)", "Write(*.production.*)" ] }}Claude Code also respects .gitignore by default (controlled by the respectGitignore setting, which defaults to true). So if something is in .gitignore, Claude Code won’t touch it unless you tell it to.
5 Analogies
- Soldier: Classified document clearance levels. You can read everything marked SECRET or below. TS/SCI? You never even see that folder exists.
- Romance: The topics you agreed to never bring up. “We don’t talk about the Barcelona trip.” It’s not that it doesn’t exist — it’s just off limits by mutual agreement.
- RPG: Locked inventory slots. Some items are quest-locked, story-locked, or character-class-locked. You can see them but you can’t touch them yet.
- Corporate: Access control policy. HR can see payroll records. Engineering can’t. It’s not a secret that payroll files exist — they’re just not in your access scope.
- Gen Z: The blocked list, no cap. Some things are just off the table. Not hidden. Not deleted. Just: not accessible to you. Full stop.
How They All Work Together
Here’s a real scenario that ties everything together.
I type /review into Claude Code.
-
CLAUDE.md is already loaded — Claude knows this is a TypeScript project with strict conventions and that
.envfiles are off-limits. -
Skill
/reviewactivates — Claude takes on the code review persona, restricted to read-only tools, using the review-specific instructions inSKILL.md. -
Hook
PreToolUsefires before Claude reads any file — the audit logger records what’s happening. -
The skill spawns an Agent to check external API documentation in parallel while it reviews the code.
-
Permissions block Claude from reading
.env.productionwhen the review touches the config layer. -
Hook
PostToolUsefires after Claude finishes each file read — the timing logger records performance data. -
Hook
Stopfires when the review completes — a script formats the output into the team’s Notion template and posts it to Slack.
Everything happened automatically from one /review command.
Here’s the relationship diagram:
Plugin (distributable package)├── Skills (knowledge + slash commands)├── Agents (sub-workers)├── Hooks (auto-triggers)├── MCP/LSP servers└── Default settings
CLAUDE.md (project memory, 6 levels)├── Loaded at session start└── Provides context for everything
Hooks → Independent, event-triggered, configured in settings.jsonPermissions → Independent, file access control in settings.jsonQuick Reference Cheat Sheet
| Component | What It Is | Location | Invoked By |
|---|---|---|---|
| CLAUDE.md | Persistent project memory | ./CLAUDE.md (6 levels) | Auto, every session |
| Skill | Expert knowledge module | .claude/skills/<name>/SKILL.md | /skill-name command |
| Command | Simple slash trigger (legacy) | .claude/commands/<name>.md | /command-name |
| Hook | Auto-triggered script | settings.json hooks section | Events (PreToolUse, etc.) |
| Agent | Specialized sub-worker | .claude/agents/<name>.md | Task tool spawn |
| Plugin | Installable bundle | .claude-plugin/plugin.json | claude plugin install |
| Permissions | File access control | settings.json permissions | Enforced automatically |
FAQ
What is a Claude Code skill?
A skill is a directory in .claude/skills/ containing a SKILL.md file that defines an expert persona, what tools it can use, and how it should behave. It becomes a slash command (e.g., /code-review) that activates that specialized behavior on demand. Think of it as giving Claude a specialized hat to wear for a specific task.
What is the difference between a Claude Code skill and plugin?
A skill is one focused capability (code review, deployment, documentation). A plugin is a distributable package that can contain multiple skills, agents, hooks, MCP servers, and settings. Skills are for building; plugins are for distribution. You build skills during development. You package them into a plugin when you want to share them.
What is CLAUDE.md and why do I need it?
CLAUDE.md is a Markdown file Claude reads at the start of every session. It contains your project conventions, architecture patterns, tech stack details, and rules. Without it, Claude Code starts every conversation from zero and has to re-learn your project. With it, you get consistent, project-aware output from the very first prompt — every time.
What are Claude Code hooks?
Hooks are scripts that run automatically when specific events occur — before a tool call, after an edit, when a session starts, when Claude finishes a turn. They’re configured in .claude/settings.json. Use them for auto-linting, blocking dangerous commands, logging all AI actions, and running tests after edits.
What are Claude Code agents?
Agents are specialized sub-workers defined in .claude/agents/. They run in their own context with their own tool restrictions, model settings, and instructions. The main Claude thread spawns them via the Task tool. They’re great for parallel work, specialized tasks, or operations you want to sandbox away from the main context.
How do I create a Claude Code skill?
- Create the directory:
mkdir -p .claude/skills/my-skill - Create the SKILL.md:
touch .claude/skills/my-skill/SKILL.md - Add YAML frontmatter and instructions:
---name: "my-skill"description: "What this skill does"user-invocable: trueallowed-tools: ["Read", "Grep"]---# My SkillYou are a specialist in...- Invoke with
/my-skill
How do I control what files Claude Code can access?
Use permissions.deny in .claude/settings.json:
{ "permissions": { "deny": [ "Read(.env)", "Read(.env.*)", "Read(secrets/**)" ] }}Note: There is no .claudeignore file — that’s a common misconception. Claude Code also respects .gitignore automatically (this can be disabled with "respectGitignore": false in settings).
Conclusion
Here’s the one-sentence version of each component:
- CLAUDE.md — the memory that makes Claude know your project
- Skills — specialized expert modes you can switch on with a command
- Commands — simple slash shortcuts (use Skills for new work)
- Hooks — automatic scripts that fire on events, no prompting needed
- Agents — sub-workers you spawn for parallel or specialized tasks
- Plugins — packaged bundles of everything above, ready to distribute
The mental model that works for me: CLAUDE.md is the foundation that everything else builds on. Skills and Agents extend what Claude can do. Hooks enforce how it behaves. Plugins package it all for sharing.
Pick ONE of these today and set it up. If you don’t have a CLAUDE.md yet, start there — 10 minutes, 20 lines, and you’ll immediately see the difference. If you already have a good CLAUDE.md, write your first hook. Auto-lint on edit or block rm -rf — either one will change how you work.
Want to go deeper? Hooks are covered in detail in Claude Code Hooks: The Power Feature Nobody Talks About. CLAUDE.md is covered in Why CLAUDE.md Is the Most Important File in Your Project.
Skills, Agents, Hooks, and Plugins are covered in depth in Phase 11: Automation & Headless and Phase 15: Templates, Skills & Ecosystem of the Claude Code Mastery course. Phases 1-3 are free.