· 13 min read ·
From command to plugin: the four levels of Claude Code
Claude Code has four pieces: commands, skills, agents and plugins. Each adds power and complexity, and there's a clear point to move up.


A project that uses Claude Code usually ends up with several of these folders: .claude/commands/, .claude/skills/, .claude/agents/, sometimes a .claude-plugin/. All of them hold markdown with YAML at the top, all of them extend what Claude can do, all of them end up in the slash menu. Most people pick one based on whatever they saw first in a tutorial, and stay there.
That works at small scale. It breaks the moment you need a second model, a specific MCP, a Python script, a reproducible output format, or a way to hand the whole thing to a teammate. At that point you either rebuild at the right level or keep stretching the one you had until it snaps.
We see this over and over with clients starting out in Claude Code. The first command works great for a week, and then someone tries to bolt on logic it was never meant to carry. Here’s the map we usually give them: one concept per level, the same example carried through all four, and a clear rule for when to move up.
These four levels are one axis: what the thing you build is made of. Who’s using it is a separate axis, with its own ladder of five levels in Claude Code proficiency levels.
The four levels, one sentence each
Every Claude Code extension fits one of these four shapes. Each one adds capability, and also coordination, so it’s worth knowing which one you’re in before you build the next.
- Command: a short markdown file at
.claude/commands/<name>.mdthat you trigger with/name. Claude decides the rest. - Skill: a folder at
.claude/skills/<name>/with an orchestrator (SKILL.md) plus scripts, references, templates and examples. - Agent: a specialized subagent at
.claude/agents/<name>.mdthat the skill dispatches. Fixed model, allowed tools, isolated context. - Plugin: a self-contained folder, usually with a
.claude-plugin/plugin.jsonmanifest, that packages commands, skills and agents so they can be distributed and versioned as one unit.
The progression tracks where the complexity actually lives. A command is a prompt. A skill is a prompt plus the files that make it deterministic. An agent is one step of a skill with its own configuration. A plugin packages commands, skills and agents so they can be distributed and versioned as a unit.
Before building anything, check what you already have. Type / in a session and you’ll see built-in commands, skills and subagents: /help, /init, /model, /agents, /skills, /plugin, among others. Claude also ships with built-in skills (simplify, debug, batch, loop) and built-in subagents (Explore, Plan, general-purpose) that dispatch on their own. Don’t rebuild what’s already there: custom work is for what’s specific to your domain, your team, your data.
One example, climbing all four levels
To make this concrete, we follow the same case through every level: tracking daily AI news. It starts as a one-line prompt and ends as a versioned plugin with parallel workers.
The first version is a command that fires once a day. By the second week it starts failing: Claude summarizes marketing posts instead of actual launches, the format changes from one run to the next, and stories covering both Twitter and TechCrunch need deduplicating. It moves up to a skill. Then the skill does too much in a single model call, so it splits into four agents. Later a teammate wants it too, so it gets packaged as a plugin.
The point of the example isn’t the news summary itself, it’s learning to notice the moment the current level stops being enough. Stretching a command past that point is where most projects get tangled.
Level 1: command, the reusable prompt
A markdown file with a short prompt you repeat day after day. You save it once and trigger it with /name. No code, no folder, just the file. You describe what you want, Claude decides how: which tool to call and in what order.
Use it when the task fits in a paragraph and you trust Claude to pick the right tools. Stop using it the moment you start copying workarounds, the result changes from run to run, or you need a specific MCP or a fixed format every time. That’s the signal to move up to a skill.
.claude/└── commands/ └── ai-news.md---description: Fetches today's top AI news---
# /ai-news
Search the web for the most important AI newsfrom the last 24 hours. Cover model launches,funding rounds, regulatory changes andrelevant research papers.
Return a short bulleted list, a one-linetakeaway per item and the source URL.Claude decides which tool to use (WebSearch in this case) from the prompt alone, with no MCP wired up and no permissions specified. That’s the point of staying at level 1.
Install it with mkdir -p .claude/commands && mv ai-news.md .claude/commands/ for the project, or in ~/.claude/commands/ for every project you work on. Run it by typing /ai-news, with arguments via /ai-news for today referenced as $ARGUMENTS or $0, $1…
The official documentation notes that commands and skills have merged: a file at commands/deploy.md and a skill at skills/deploy/SKILL.md both create /deploy and behave the same way.
Level 2: skill, the command with scaffolding
When a command outgrows a paragraph, turn it into a skill: a folder with one required file (SKILL.md) and whatever scripts, references, templates or examples it needs. SKILL.md is the orchestrator: it tells Claude what the skill does, when to use it, which scripts to run, which references to read and what output to produce. Every other file is passive support, Claude only loads it when SKILL.md asks for it.
There’s no mandatory subfolder naming, but conventions have settled in. scripts/ holds Python or bash for deterministic logic. references/ holds documents Claude reads when SKILL.md tells it to. templates/ are files Claude fills in. examples/ set the tone and structure to follow. assets/ is for static binaries.
Here’s how /ai-news ended up split into folders once it stopped being enough as a standalone command:
.claude/skills/└── ai-news/ ├── SKILL.md ← orchestrator: when to run, what to call, output format ├── scripts/ │ ├── dedupe.py ← groups articles about the same story across sources │ └── classify.py ← tags each story by category ├── references/ │ ├── trusted-sources.md ← whitelist of feeds │ └── taxonomy.md ← category definitions ├── templates/ │ └── brief.md ← the exact shape of the output └── examples/ └── 2026-04-12-brief.md ← a previous run kept as referenceSKILL.md stitches it all together: reads trusted-sources.md first, runs per-source searches, runs dedupe.py, runs classify.py, and fills in templates/brief.md following the example. It triggers the same way a command does, either with /ai-news or by letting Claude pick it on its own from its description.
Of the frontmatter fields, the most useful are: description (when to auto-invoke, put the main use case first), disable-model-invocation: true (manual-only skill, good for anything with side effects like /deploy), allowed-tools (pre-approves tools), model and effort (the model and reasoning budget for the turn), and context: fork (runs in an isolated subagent without polluting the main context).
Skills are folders: they live in .claude/skills/<name>/ (project) or ~/.claude/skills/<name>/ (user), and they hot-reload during the session, no restart needed. That said, SKILL.md stays loaded in context for the rest of the session, so it’s worth keeping it short (the documentation recommends under 500 lines) and pushing long references into separate files that only load when needed.
Level 3: agent, the specialized worker
A skill’s orchestrator is still one big model call. When you need step-by-step control (fixing a model, restricting tools, capping reasoning effort, isolated context), the work splits into subagents: the skill dispatches, and each agent has its own system prompt, model, tools and clean context window.
Reach for agents when different steps want different models (opus for creative work, haiku for operations), when you want to fix tools per step, or when you want parallel work distribution. Skip them when everything runs fine in a single context with a single model.
An agent file is a markdown at .claude/agents/<name>.md with frontmatter: name and description are required (the description is the “use when…” sentence that decides dispatch), model fixes opus / sonnet / haiku, tools is the permission list, effort is the reasoning budget, maxTurns caps the agentic loop, and isolation: worktree runs the agent in a temporary git worktree.
The skill version got the format right, but each run was still one big call doing very different jobs: noisy scraping, fuzzy deduplication, writing. It split into four agents, dispatched in parallel from SKILL.md:
ai-news-scraperonhaiku, low effort, onlyWebFetchandWebSearch: fetches articles from one source, runs × 8 in parallel.ai-news-dedupeonhaiku, low effort,ReadandBash: runsdedupe.py.ai-news-categorizeonsonnet, medium effort: tags each story against the taxonomy.ai-news-editoronopus, high effort: writes the final summary with one takeaway per story.
The orchestrator dispatches the 8 scrapers in parallel, waits, hands the combined feed to dedupe, then to categorize, then to the editor. Total time drops from about 3 minutes to about 40 seconds, and the writing comes out sharper running on opus instead of inheriting a session leaning on haiku.
It installs the same way as a command but under agents/, and like skills it reloads on its own: changes to a subagent file apply within a few seconds, and a session restart is only needed if the agents/ folder didn’t exist at startup. You don’t “run” an agent, you dispatch it: automatically when its description matches the task, with @agent-ai-news-editor to force it, or with claude --agent ai-news-editor for a whole session under its configuration. One nuance about nesting: a subagent can launch other subagents, because it inherits the Agent tool unless it declares a tools list; if that list omits Agent, parallel distribution has to come from the main session.
Level 4: plugin, the distributable package
By now you have commands in one folder, a skill in another and agents in a third. They belong together, but by default anything in .claude/agents/ is visible to any task in the project, even when the skill that uses it isn’t running.
A plugin solves the packaging problem: it groups commands, skills and agents into one installable unit, what most people just call Claude Code plugins. Agents only exist within the plugin’s scope, the command and skill get discovered when the plugin is active and hidden when it isn’t. Package it as a plugin when the pieces are coupled or you want to version the set as one unit. Keep it loose while you’re still iterating fast or the agents could be reused somewhere else.
plugin-root/├── .claude-plugin/│ └── plugin.json ← manifest├── commands/ ← level 1├── skills/<name>/ ← level 2└── agents/ ← level 3With the four ai-news-* agents visible across the whole project and a teammate wanting the same setup, it’s time to package it. Along the way, a few more entries get added: a weekly digest and a deep-dive command by topic, all three backed by the same skill and the same agents.
ai-news-radar/ ← plugin root├── .claude-plugin/│ └── plugin.json ← name, version, description├── commands/ ← three entries (namespaced on install)│ ├── ai-news.md ← daily digest│ ├── ai-news-weekly.md ← weekly roundup│ └── ai-news-deep.md ← deep dive├── skills/ai-news/SKILL.md ← orchestrator (namespaced)├── agents/ ← 4 specialists, plugin-scoped only│ ├── ai-news-scraper.md│ ├── ai-news-dedupe.md│ ├── ai-news-categorize.md│ └── ai-news-editor.md├── scripts/├── references/└── templates/agents/, commands/ and skills/ at the root get discovered automatically on install, no need to list them in the manifest: only plugin.json goes inside .claude-plugin/.
For local development, claude --plugin-dir ./ai-news-radar loads the plugin from disk with no install or marketplace, and /reload-plugins applies changes within the session. For a teammate’s plugin, you add the source as a marketplace and install it by name:
/plugin marketplace add your-team/team-skills/plugin install ai-news-radar@team-skills/plugin enable ai-news-radar@team-skillsUpdates apply with /plugin update or with the automatic update. The /plugin selector asks for scope: user (every project you work on, the default), project (.claude/settings.json, versioned and shared with the team) or local (.claude/settings.local.json, just for you in that repo).
A plugin itself doesn’t run, what runs is whatever it contains. Its commands and skills show up namespaced with the plugin’s name, so two plugins can each have a command called commit without colliding: /ai-news-radar:ai-news, @agent-ai-news-radar:ai-news-editor. Use .claude/ while you iterate, promote to a plugin once it stabilizes and you want to ship it.
Six common mistakes when starting out
- A plugin’s components go at the root, not inside
.claude-plugin/. Putagents/,commands/,skills/andhooks/at the same level as.claude-plugin/. Onlyplugin.jsongoes inside it. - A plugin’s skills get namespaced. A skill at
my-plugin/skills/hello/SKILL.mdbecomes/my-plugin:hello, not/hello. This keeps two plugins from colliding on the same name. - Hot-reload almost everywhere. A subagent
.mdedited on disk reloads on its own within seconds (restart only ifagents/didn’t exist at startup);SKILL.mdreloads on the next invocation; plugins use/reload-plugins. - Subagents inherit dangerous permission modes. If the main session is in
bypassPermissionsoracceptEdits, that overrides the subagent’s ownpermissionMode, even if it saysdefault. - A plugin’s subagents ignore three fields. For security,
hooks,mcpServersandpermissionModeare ignored inside a plugin. If you need them, the file has to live in a standalone.claude/agents/. - A plugin’s install paths are ephemeral. On update, its
${CLAUDE_PLUGIN_ROOT}changes and the previous version gets cleaned up within a few days. For persistent state, use${CLAUDE_PLUGIN_DATA}.
The decision matrix
The common mistake is starting too high up. The right move is to start at the lowest level that solves the problem in front of you, and move up only when something concrete stops working.
| If you notice… | Go to | Except when… |
|---|---|---|
| You rewrite the same prompt every day | command | the prompt changes from run to run: move up to skill |
| The output changes shape, you need an MCP or a fixed format every time | skill | (no exception) |
| You need a script or references loaded ahead of time | skill | the script is one-off: keep it next to the command |
| Different steps want different models or tools | agents | one model works for everything: stay at skill |
| You want parallel work from the orchestrator | agents | the steps are sequential anyway |
| Several commands share a skill and coupled agents | plugin | you’re still iterating fast: defer the manifest |
| Your teammate needs the same setup, versioned | plugin | it’s a one-off you won’t maintain |
If you’re torn between two levels, start at the lower one. It costs far less to undo a one-line command than to take apart a half-built plugin.