Skills
A skill is a folder with a markdown file that tells Claude how to do one job and loads only when that job comes up.
Last updated: 29 Sep, 2026 · Claude Code
That last part is the reason skills exist rather than more CLAUDE.md. CLAUDE.md is in context all session, every session. A skill's body is loaded when it is used, so you can have twenty of them and pay only for their descriptions until one is needed.
The video defines a skill as a reusable collection of instructions, resources and examples that teach Claude Code how to complete a specific type of task. The flow on its slide: you describe a task, Claude selects the most relevant skill from your request and context, the skill's instructions run with whatever resources, plugins or tools they need, and the result comes back. A job you repeat in every project is the one to turn into a skill.
One skill
---
name: release-notes
description: Write release notes from the commits since the last tag. Use when preparing a release or when asked what changed.
allowed-tools: Bash(git log:*) Read
---
1. Find the last tag with `git describe --tags --abbrev=0`.
2. Read `git log <tag>..HEAD --oneline`.
3. Group the commits into Added, Fixed and Changed.
4. Write one line per entry, in plain language, no commit hashes.
5. Leave out anything that only touched tests or formatting.The frontmatter is the interface. name is what you type after a slash, and it defaults to the folder name. description is what Claude reads when deciding whether this skill applies to your request. allowed-tools lists what it may use without stopping to ask, for the turn that invoked it.
The body is a numbered procedure, and it reads like instructions to a person who is capable but new. Not an essay about release notes: the actual steps, in order.
The description does the routing
Say what changed since the last release? and Claude picks this skill because the description mentions release notes and when to use them. A description like release notes helper would not have been enough. This is the same lesson as tool descriptions: the words are the interface.
If you would rather it never fired on its own, set disable-model-invocation: true and it only runs when you type /release-notes.
Check it before you trust it
A broken skill fails without an error: it never gets picked, and it looks as if Claude ignored you. A short checker reads the skill file above and reports the three things that decide whether a skill is ever used.
Reading the skill file
The checker starts from the file a skill lives in.
# load the whole SKILL.md as text
skill = open("SKILL.md").read()Splitting frontmatter from the body
Frontmatter sits between two --- lines at the top of the file; the rest is the procedure.
def frontmatter(text):
if not text.startswith("---"):
return {}, text # no header: the whole file is content
end = text.find("\n---", 3)
head, body = text[4:end], text[end + 4:]
fields = {}
for line in head.splitlines():
if ":" in line: # each "key: value" line
key, value = line.split(":", 1)
fields[key.strip()] = value.strip()
return fields, bodyCounting the parts that matter
With the header parsed, it measures the three things that decide whether a skill is picked: the name, the description length, and the body size.
fields, body = frontmatter(skill)
lines = [l for l in body.splitlines() if l.strip()] # non-empty body lines
print("name: ", fields.get("name", "(the folder name)"))
print("description:", len(fields.get("description", "")), "characters")
print("body: ", len(lines), "non-empty lines")Warning on the common mistakes
Then it flags the failures that stop a skill from ever being picked: no frontmatter, a thin description, a heavy body, or no numbered steps.
if not fields:
print("PROBLEM: no frontmatter. The whole file is content.")
if "description" not in fields:
print("PROBLEM: no description, so Claude has to guess.")
elif len(fields["description"]) < 40:
print("WEAK: it says what this is, not when to use it.")
if len(lines) > 40:
print("HEAVY: this body loads whenever the skill runs.")
if not any(l.strip()[:1].isdigit() for l in lines):
print("VAGUE: no numbered steps. A skill is a procedure.")Running the checker on a real skill
"""Check a SKILL.md before you trust it.
Three things decide whether a skill is ever used: valid
frontmatter, a description that says when to use it, and a
body short enough to be cheap.
"""
skill = open("SKILL.md").read()
def frontmatter(text):
if not text.startswith("---"):
return {}, text
end = text.find("\n---", 3)
head, body = text[4:end], text[end + 4:]
fields = {}
for line in head.splitlines():
if ":" in line:
key, value = line.split(":", 1)
fields[key.strip()] = value.strip()
return fields, body
fields, body = frontmatter(skill)
lines = [l for l in body.splitlines() if l.strip()]
print("name: ", fields.get("name", "(the folder name)"))
print("description:", len(fields.get("description", "")), "characters")
print("body: ", len(lines), "non-empty lines")
print()
if not fields:
print("PROBLEM: no frontmatter. The whole file is content.")
if "description" not in fields:
print("PROBLEM: no description, so Claude has to guess.")
elif len(fields["description"]) < 40:
print("WEAK: it says what this is, not when to use it.")
if len(lines) > 40:
print("HEAVY: this body loads whenever the skill runs.")
if not any(l.strip()[:1].isdigit() for l in lines):
print("VAGUE: no numbered steps. A skill is a procedure.")name: release-notes description: 113 characters body: 5 non-empty lines
The frontmatter has to start on the very first line of the file, or the file is treated as content and none of the fields exist. That mistake explains many skills that do nothing, and it is the first thing the checker looks for.
A skill that calls MCP tools
The video asks Claude to create a research-topic skill that researches a topic with two search providers, Exa and the built-in web search, and to write it as SKILL.md in the project. Claude writes .claude/skills/research-topic/SKILL.md. The preview of its body, as the video shows it (the frontmatter is not on screen):
# Research Topic (Exa + WebSearch)
Given a topic, research it using two independent search providers — the Exa
MCP server and the built-in WebSearch tool — then combine, dedupe, and
cross-validate their results into a single concise, well-sourced overview.
## Input
The topic is taken from, in order of preference:
1. The argument passed to /research-topic <topic>.
2. The topic named in the user's natural-language request.
## Workflow
1. Frame the query. ...
2. Search with BOTH providers — in parallel. ...
- Exa: mcp__exa__web_search_exa with { "query": "<your query>", "numResults": 5 }
- WebSearch: the built-in WebSearch tool with the same (or a lightly rephrased) query.
3. Merge and dedupe. ...
4. Cross-validate. ...
5. Synthesize. ...The body names an MCP tool, mcp__exa__web_search_exa, next to a built-in one. MCP tools are named mcp__<server>__<tool>, and a tool from a server that a plugin installed carries the plugin's name too: mcp__plugin_<plugin>_<server>__<tool> (MCP). Use the full name wherever a skill lists tools in allowed-tools.
Running it as /research-topic What are LLM Gateways shows what happens when a tool is missing. Claude loads the search tools and reports that the Exa tools are not callable yet: the Exa MCP server is installed but needs a one-time OAuth login, so only its authenticate tool is exposed. Following the skill's fallback, it runs web searches only and still writes the overview of LLM gateways. The video points out the fix: sign in to Exa once.
Setting up Exa for the research skillOptional
Exa is a paid search API with free credits for new accounts; you need it only if you want the skill's Exa half. It installs as a plugin from Anthropic's official marketplace, which bundles its MCP server (Exa MCP):
claude plugin install exa@claude-plugins-officialStart a session, run /mcp, choose the Exa server and sign in when the browser opens. That is the one-time login the video's run was missing. The plugins lesson covers installing from the marketplace in more detail: Plugins.
Related
- Previous: Custom slash commands
- Next: Statusline and output styles
- Change the description in the panel to two words and run the checker again.
- Write a skill for the most annoying repeated job in your own project.
Slow is fine. Stopping is the only problem.