Section 15 covered the basic idea of a skill. Here is the full mechanism: when and how Claude loads a skill, the frontmatter fields, arguments, scripts, and what happens from installing a plugin to loading it in a session. (Details follow the Claude Code docs.)
17.1 Skill lifecycle — what happens in one request
How a skill gets triggered
1.1. Session start: only each skill's name + description are in context
↓→
2.2. User prompt: "write the release notes"
↓→
3.3. Claude matches: compares the prompt ↔ descriptions
↓→
4.4. SKILL.md loads: the full body now enters the context
↓→
5.5. Extra files / scripts: read or run when needed
↓→
6.6. Result: the answer follows the skill's instructions
The description is the trigger — it decides when the skill runs
That is why description is the most important field. Claude does not have the skill's body until it loads it — it decides only by looking at the description. If the description does not clearly say "when to use", the skill will never trigger (or will trigger in the wrong place).
17.2 Where skills live and which has higher priority
Location
Path
For whom
Enterprise
In the managed settings directory .claude/skills/<name>/SKILL.md
The whole organization
Personal
~/.claude/skills/<name>/SKILL.md
All your projects
Project
.claude/skills/<name>/SKILL.md
Everyone on this repo (committed to git)
Nested
<subdir>/.claude/skills/<name>/SKILL.md
When working in that folder
Plugin
<plugin>/skills/<name>/SKILL.md
Wherever the plugin is enabled
claude.ai account
Skills enabled on the account
Sessions logged in with that account
If names are the same, priority: Enterprise > Personal > Project.
A skill overrides a .claude/commands/ file and a bundled skill of the same name.
Plugin skills are always namespaced (/plugin-name:skill-name), so they never clash with anything.
17.3 SKILL.md frontmatter — important fields
Field
What it does
name
Command name (/name). If omitted, the folder name is used
description
What it does + when to use it. Claude decides from this
when_to_use
Extra trigger context, appended to the description
disable-model-invocation: true
Claude cannot run it itself — only the user via /name. The description is not even put in context
user-invocable: false
Hidden from the / menu — only Claude uses it itself
allowed-tools
No permission prompt for these tools during the skill's turn (ends at the next message)
disallowed-tools
These tools are blocked while the skill is active
argument-hint, arguments
Autocomplete hint ([issue-number]), named arguments
model, effort
Override model / effort for that turn
context: fork + agent
Run the skill in a separate subagent (e.g. agent: Explore) — main context stays clean
paths
Glob patterns — auto-activates only when working on matching files
hooks
Register hooks when the skill is invoked
shell
bash (default) or powershell
17.4 Who can run it — invocation control
Setting
User via /name?
Claude itself?
When to use
Default
Yes
Yes
Most skills
disable-model-invocation: true
Yes
No
Deploy, commit, risky or manual work
user-invocable: false
No
Yes
Background knowledge (e.g. coding conventions)
17.5 Arguments and variables
---
name: fix-issue
description: Takes a GitHub issue number and fixes it
argument-hint: [issue-number]
disable-model-invocation: true
---
Fix GitHub issue $ARGUMENTS according to our coding standards.
1. Read the details with `gh issue view $ARGUMENTS`
2. Fix it, run the tests, commit
A named argument given in the arguments: frontmatter
${CLAUDE_SKILL_DIR}
The skill's folder (for building script paths)
${CLAUDE_PROJECT_DIR}, ${CLAUDE_SESSION_ID}
Project folder, session ID
No placeholder
Claude Code appends ARGUMENTS: <value> at the end
17.6 Supporting files and scripts
release-notes/
├── SKILL.md # required — main instructions (keep under 500 lines)
├── reference.md # read when needed
├── template.md # read when needed
└── scripts/
└── collect_commits.py # RUN, not read — only its output enters the context
Mention these files in SKILL.md ("see template.md for the format") so Claude knows when to open them.
The script's code does not enter the context, only its output — so keeping big logic in a script saves tokens and is deterministic.
To run a script without a permission prompt use allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/collect_commits.py *).
17.7 A complete example skill
---
name: release-notes
description: Creates user-friendly release notes from Git commits. Use when the user
asks for release notes, a changelog, or "what's new in this release".
argument-hint: [from-tag]
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/collect_commits.py *)
---
# Release Notes
1. Run `${CLAUDE_SKILL_DIR}/scripts/collect_commits.py $ARGUMENTS` — it returns the commits as JSON.
2. Split the commits into Features / Fixes / Breaking Changes.
3. Follow `template.md` for the format.
4. Remove technical jargon; write for end users.
17.8 Limits and behaviours to remember
Point
Detail
Description limit
description + when_to_use are cut at 1,536 characters in the listing — put the main use case first
Live reload
Adding/editing/deleting a skill applies to the current session immediately; if it is a new top-level skills folder, run /reload-skills
After compaction
The first 5,000 tokens of each invoked skill are kept (total budget 25,000)
allowed-tools
Pre-approval for that turn only
Commands vs skills
Both .claude/commands/deploy.md and .claude/skills/deploy/SKILL.md create /deploy; skills add: supporting files, invocation control, auto-loading
"Reviews SQL Server queries for performance and security. Use when the user shares a SQL query, stored procedure or execution plan."
"Does stuff with PDFs"
"Extracts text/tables from PDFs, merges/splits PDFs. Use when the user mentions a .pdf file or wants to create a PDF."
17.10 What a plugin is and when you need one
A plugin is a folder containing skills, agents (subagents), hooks, MCP servers (and a few other components), plus a manifest .claude-plugin/plugin.json. Claude Code installs and loads it as one unit.
Situation
What to use
Just one skill / hook for yourself
Standalone: ~/.claude/skills/, hooks in settings
For the team of one repo
The project .claude/ folder (in git)
Sharing several skills + hooks + MCP together
Plugin
Versioned releases across many projects / the whole org
// my-first-plugin/.claude-plugin/plugin.json
{
"name": "my-first-plugin", // required; becomes the prefix of every skill/agent, no spaces
"description": "A greeting plugin to learn the basics",
"version": "1.0.0", // optional; if set, users stay on this exact version
"author": { "name": "Your Name" }
}
<!-- my-first-plugin/skills/hello/SKILL.md -->
---
name: hello
description: Greet the user with a friendly message
disable-model-invocation: true
---
Greet the user warmly and ask how you can help them today.
claude plugin validate ./my-first-plugin # "✔ Validation passed"
claude --plugin-dir ./my-first-plugin # load for this session only (not installed)
# in the session:
/my-first-plugin:hello
/reload-plugins # edited the files? reload
Shortcut: claude plugin init my-tool → creates a starter plugin in ~/.claude/skills/my-tool/ that auto-loads in every session (my-tool@skills-dir). To turn an existing .claude/ setup into a plugin, copy commands/, agents/, skills/ and put the hooks object from settings into hooks/hooks.json.
17.15 Creating and sharing a marketplace
// my-marketplace/.claude-plugin/marketplace.json
{
"name": "my-marketplace",
"description": "Plugins for my team",
"owner": { "name": "Your Name" },
"plugins": [
{
"name": "my-first-plugin", // keep it the same as the name in plugin.json
"source": "./plugins/my-first-plugin", // path relative to the marketplace root
"description": "A greeting plugin to learn the basics"
}
]
}
claude plugin validate ./my-marketplace
claude plugin marketplace add ./my-marketplace # or GitHub: owner/repo
claude plugin install my-first-plugin@my-marketplace # id = <entry-name>@<marketplace>
claude plugin list # Status: ✔ enabled
claude plugin details my-first-plugin # component inventory
From any git URL, zip, npm package, or command output
—
17.16 Install scopes and settings
Scope
Where it is written
For whom
User
~/.claude/settings.json
You, every project
Project
.claude/settings.json (in git)
Everyone on the repo (each person installs on their own machine)
Local
.claude/settings.local.json
Only you, only in this repo
Managed
Org policy
Force-enable or block — nobody can override
// .claude/settings.json — enable the plugin for the team
{
"enabledPlugins": {
"my-first-plugin@my-marketplace": true
}
}
Precedence (low → high): --add-dir → user → project → local → --settings flag → managed. The project enabled it but you do not want it? Set it to false in .claude/settings.local.json.
17.17 The plugin ID tells you where it came from
End of the ID
Meaning
@<marketplace>
Installed from a marketplace
@inline
From --plugin-dir / --plugin-url / the Agent SDK — that session only
@skills-dir
A plugin folder in ~/.claude/skills/ or .claude/skills/
@synced
A plugin enabled on the claude.ai account, synced into Claude Code
17.18 Versions, updates and paths
If you pin a version in plugin.json, users stay on it until you change the version string. If you do not, the git commit SHA becomes the version (every commit = an update).
Auto-update: on by default for official marketplaces, off for others. After an update, /reload-plugins or restart.
${CLAUDE_PLUGIN_ROOT} = the plugin's installed version folder (changes with every version) — use it for script paths in hooks/MCP config.
${CLAUDE_PLUGIN_DATA} = a persistent data folder that survives updates — keep cache and config here.
A plugin cannot load components from a path outside its own folder (../shared).
17.19 Debug checklist
claude plugin validate <path> — checks the manifest and every skill/agent frontmatter.
In the session /reload-plugins — applies edits; then run /plugin-name:skill and see.
/plugin → Installed tab (components list) and Errors tab (what did not load and why).
MCP server: status in /mcp. Hook: trigger the event and read the debug log.
Plugin loaded but Claude's behaviour did not change? Compare with/without the plugin using claude plugin eval.