Overview
Skills are the core building blocks of Claude Code plugins. A skill is a single markdown file named SKILL.md that tells Claude how to perform a specific task — code review, database migration, security scanning, or anything else you can express in structured instructions. When Claude detects that your request matches a skill’s trigger conditions, it loads the skill automatically and follows its methodology.
This guide explains the anatomy of a SKILL.md file, walks you through building one from scratch, and shows how to test and refine it until it performs reliably.
What is a SKILL.md file
A SKILL.md file lives inside a plugin at skills/<skill-name>/SKILL.md. It contains two parts:
- YAML frontmatter — metadata that tells Claude Code when and how to load the skill.
- Markdown body — the actual instructions Claude follows when the skill activates.
Here is a minimal example:
---
name: quick-lint
description: |
Run a fast lint check on the current file. Use when the user asks
to lint, check style, or fix formatting issues.
allowed-tools: Read, Bash(npx:eslint)
version: 1.0.0
author: Your Name <you@example.com>
license: MIT
---
## Overview
You are a code linting specialist. When activated, run ESLint on the
target file and report results in a structured format.
## Steps
1. Identify the file to lint from the user's request.
2. Run `npx eslint <file> --format stylish` using the Bash tool.
3. Parse the output and summarize findings.
4. If there are auto-fixable issues, offer to run `npx eslint <file> --fix`.
When a user says “lint this file” or “check the formatting,” Claude matches those phrases against the skill’s description field and loads the instructions.
Frontmatter schema
Every SKILL.md starts with a YAML frontmatter block delimited by ---. The following fields are supported.
Required fields
| Field | Type | Description |
|---|---|---|
name | string | Unique identifier for the skill (kebab-case) |
description | string | When to use this skill. Include trigger phrases that Claude matches against. |
allowed-tools | string | Comma-separated list of tools the skill can use |
version | string | Semantic version (e.g., 1.0.0) |
author | string | Author name and optional email |
license | string | SPDX license identifier (e.g., MIT, Apache-2.0) |
Optional fields
| Field | Type | Description |
|---|---|---|
model | string | Override the LLM model (sonnet, haiku, opus) |
context | string | Set to fork to run in a subagent context |
agent | string | Subagent type (e.g., Explore) |
user-invocable | boolean | Set to false to hide from the / menu |
argument-hint | string | Autocomplete hint shown in the / menu |
hooks | object | Lifecycle hooks (e.g., pre-tool-call) |
compatibility | string | Environment requirements (e.g., Node.js >= 18) |
compatible-with | string | Platform compatibility (claude-code, cursor) |
tags | array | Discovery tags for search and categorization |
The description field matters most
The description is the single most important field. Claude uses it to decide whether to activate the skill. Write it as a natural-language explanation of when the skill should fire, including specific trigger phrases:
description: |
Perform a security audit on JavaScript or TypeScript code. Use when the
user asks to check for vulnerabilities, audit security, scan for XSS,
or review authentication logic.
Poor descriptions that are too vague (“helps with code”) or too narrow (“only for React useState hooks”) cause skills to either fire too often or never fire at all.
The allowed-tools field
This field is a whitelist of the tools Claude is permitted to use when the skill is active. Valid tools:
Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch,
Task, TodoWrite, NotebookEdit, AskUserQuestion, Skill
You can scope Bash to specific commands for tighter security:
allowed-tools: Read, Edit, Bash(npm:*, npx:*, git:status)
This allows the skill to run any npm or npx command and git status, but nothing else.
Markdown body structure
The body after the frontmatter closing --- is the instruction set Claude follows. Use standard markdown with clear section headings.
Recommended sections
A well-structured skill body includes these sections:
## Overview
What this skill does and its core methodology.
## Steps
Numbered step-by-step procedure Claude follows.
## Output
The format and structure of the skill's output.
## Constraints
Boundaries, edge cases, and things to avoid.
## Examples
Concrete input/output examples that calibrate Claude's behavior.
You do not need every section in every skill. A simple linter skill might only need Overview and Steps. A complex security auditor benefits from all five.
Writing effective instructions
Skills are prompt engineering. The same principles that make a good system prompt make a good skill body:
- Be specific. “Review the code” is weak. “Check for SQL injection, XSS, CSRF, insecure deserialization, and broken authentication” is strong.
- Use numbered steps. Claude follows numbered procedures more reliably than prose paragraphs.
- Show the output format. If you want structured output, include a template or example.
- Set boundaries. Tell Claude what not to do. “Do not modify files unless explicitly asked” prevents unwanted side effects.
Referencing supporting files
Skills can reference other markdown files in the same skill directory using relative links:
For the complete API reference, see [API docs](reference.md).
For usage examples, see [examples](examples/patterns.md).
Claude follows these links using the Read tool when it needs the referenced content. This keeps your main SKILL.md focused while allowing deep-dive documentation in supporting files.
For bash commands or dynamic context injection, use the ${CLAUDE_SKILL_DIR} variable to reference the skill’s directory:
!`cat ${CLAUDE_SKILL_DIR}/templates/report.md`
Build a skill from scratch
Let us build a practical skill: a code review assistant that evaluates pull request diffs against a quality checklist.
Step 1: Create the directory structure
Inside your plugin directory, create the skill folder:
mkdir -p skills/pr-review
Step 2: Write the SKILL.md
Create skills/pr-review/SKILL.md:
---
name: pr-review
description: |
Review code changes for a pull request. Use when the user asks to
review a PR, check a diff, evaluate code changes, or assess code
quality before merging.
allowed-tools: Read, Bash(git:*), Grep, Glob
version: 1.0.0
author: Your Name <you@example.com>
license: MIT
tags: [code-review, pull-request, quality]
---
## Overview
You are an expert code reviewer. When activated, analyze the current
git diff or a specified PR and evaluate changes against a structured
quality checklist. Provide actionable, specific feedback -- not
generic advice.
## Steps
1. Determine the scope of the review:
- If the user specifies a branch or PR number, use
`git diff main...<branch>` to get the diff.
- If no branch is specified, use `git diff --staged` for staged
changes or `git diff` for unstaged changes.
2. Read the diff output and identify all changed files.
3. For each changed file, evaluate against this checklist:
- **Correctness**: Does the logic do what it claims?
- **Error handling**: Are failure cases covered?
- **Security**: Any hardcoded secrets, SQL injection, or XSS risks?
- **Performance**: Any O(n^2) loops, missing indexes, or redundant I/O?
- **Readability**: Are names clear? Is complexity justified?
- **Tests**: Are new code paths covered by tests?
4. Search for related test files using Glob and Grep to verify
test coverage for changed functions.
5. Produce a structured review report.
## Output
Format the review as follows:
### Summary
One paragraph overview of the changes and overall quality assessment.
### Findings
For each issue found:
**[SEVERITY] File:Line -- Title**
Description of the issue and why it matters.
Suggested fix with a code snippet if applicable.
Severity levels:
- **CRITICAL** -- Must fix before merge (security, data loss, crashes)
- **WARNING** -- Should fix (bugs, performance, maintainability)
- **SUGGESTION** -- Nice to have (style, naming, minor improvements)
- **PRAISE** -- Highlight well-written code worth calling out
### Verdict
APPROVE, REQUEST CHANGES, or NEEDS DISCUSSION with a one-line rationale.
## Constraints
- Do not modify any files. This is a read-only review.
- Do not review generated files (lockfiles, build output, vendor).
- If the diff is larger than 500 lines, summarize by file and focus
detailed review on the highest-risk changes.
- Always include at least one PRAISE item to acknowledge good work.
Step 3: Add the plugin manifest
If you do not already have a plugin, create the manifest at .claude-plugin/plugin.json:
{
"name": "my-code-tools",
"version": "1.0.0",
"description": "Personal code quality tools for Claude Code",
"author": "Your Name <you@example.com>",
"license": "MIT"
}
Also create a README.md at the plugin root:
# My Code Tools
Personal code quality plugins for Claude Code.
## Skills
- **pr-review** -- Structured pull request code review with quality checklist.
Your directory structure should look like this:
my-code-tools/
.claude-plugin/
plugin.json
README.md
skills/
pr-review/
SKILL.md
Test the skill
Validate the structure
Run the validator to catch structural issues before testing in Claude Code:
# Using ccpi
ccpi validate skills/pr-review/SKILL.md
# Using the universal validator (if in the Tons of Skills repo)
python3 scripts/validate-skills-schema.py --enterprise skills/pr-review/
The validator checks frontmatter fields, required sections, allowed-tools syntax, and overall content quality.
Test in Claude Code
Install your plugin locally and try the skill:
# Start Claude Code in a project with uncommitted changes
claude
# Ask for a review
Review the changes I have staged for commit.
If the skill activates, you will see Claude follow the methodology defined in your SKILL.md — reading the diff, evaluating each file against the checklist, and producing a structured report.
If the skill does not activate, check:
- Is the plugin installed? Run
/plugin listinside Claude Code. - Does the
descriptionfield match your request phrasing? Try using the exact trigger phrases from the description. - Are there errors in the frontmatter? Run
ccpi validateto check.
Iterate and improve
Skills rarely work perfectly on the first try. Here is how to refine them.
Tune the description
If the skill fires too often, narrow the trigger phrases. If it never fires, broaden them. The description should cover the most common ways a user would phrase the request.
Add examples
Including input/output examples in the body dramatically improves consistency:
## Examples
### Example: Small TypeScript PR
Input: `git diff main...feature/auth-refactor`
Expected output structure:
- Summary: "Refactors authentication middleware to use JWT validation..."
- 2-3 findings with severity, file, line, and suggested fix
- Verdict: APPROVE or REQUEST CHANGES
Use dynamic context injection
For skills that need runtime information, use DCI to inject data at activation time:
## Context
Current branch and recent commits:
!`git branch --show-current`
!`git log --oneline -5`
The ! backtick syntax runs the command when the skill loads and injects the output into the prompt. This saves tool-call round trips and gives Claude immediate context.
Reference supporting files
For complex skills, break instructions into multiple files:
skills/pr-review/
SKILL.md # Main instructions
checklist.md # Detailed quality checklist
examples/
typescript.md # TypeScript-specific review examples
python.md # Python-specific review examples
Reference them from SKILL.md with relative links:
For the full quality checklist, see [checklist](checklist.md).
For language-specific guidance, see [TypeScript examples](examples/typescript.md).
Common patterns
Subagent delegation
For expensive or long-running skills, run them in a forked context so they do not consume the main conversation’s token budget:
context: fork
agent: Explore
Model override
If a skill needs stronger reasoning (e.g., complex security analysis), override the model:
model: opus
For simple, high-volume tasks (e.g., formatting checks), use a faster model:
model: haiku
Scoped Bash access
Limit Bash access to only the commands the skill needs:
allowed-tools: Read, Bash(npm:test, npm:run, git:diff, git:log)
This follows the principle of least privilege and prevents the skill from accidentally running destructive commands.
Next steps
- ccpi CLI Quick Reference — validate and manage skills from the command line.
- Browse existing skills — study the 2,834 skills in the marketplace for patterns and inspiration.
- Explore plugins — see how production plugins structure their skills.