Lesson 10: Skills
What Are Skills?
Skills are reusable prompt templates that extend what Claude Code can do. You create a SKILL.md file with instructions, and Claude adds it to its toolkit — loading the skill automatically when relevant, or letting you invoke it directly with /skill-name.
Think of skills as building blocks for Claude's behavior. A CLAUDE.md file tells Claude how to work in your project. A skill tells Claude how to perform a specific task. If you find yourself typing the same kind of prompt repeatedly — code reviews, deploys, commit messages — that prompt belongs in a skill.
Skills follow the Agent Skills open standard, which works across multiple AI tools. Claude Code extends the standard with features like invocation control, subagent execution, and dynamic context injection.
Migrating from commands? If you have files in
.claude/commands/, they still work. Skills are the evolution of commands — same concept, more capabilities. A file at.claude/commands/review.mdand a skill at.claude/skills/review/SKILL.mdboth create/reviewand work the same way. If both exist with the same name, the skill takes precedence.
The SKILL.md Architecture
Each skill lives in its own directory with a SKILL.md file as the entrypoint:
my-skill/
├── SKILL.md # Main instructions (required)
├── template.md # Template for Claude to fill in
├── examples/
│ └── sample.md # Example output showing expected format
└── scripts/
└── validate.sh # Script Claude can executeThe SKILL.md file has two parts:
- YAML frontmatter (between
---markers) — metadata that tells Claude when and how to use the skill - Markdown content — the instructions Claude follows when the skill is invoked
Here is a minimal example:
---
name: explain-code
description: Explains code with visual diagrams and analogies. Use when explaining how code works or when the user asks "how does this work?"
---
When explaining code, always include:
1. **Start with an analogy**: Compare the code to something from everyday life
2. **Draw a diagram**: Use ASCII art to show the flow or relationships
3. **Walk through the code**: Explain step-by-step what happens
4. **Highlight a gotcha**: What's a common mistake or misconception?
Keep explanations conversational. For complex concepts, use multiple analogies.The only required file is SKILL.md. Supporting files (templates, examples, scripts, reference docs) are optional and let you build more powerful skills without bloating the main file.
Tip: Keep
SKILL.mdunder 500 lines. Move detailed reference material to separate files and reference them so Claude knows when to load them.
Where Skills Live
Where you store a skill determines who can use it:
| Location | Path | Applies To |
|---|---|---|
| Enterprise | Managed settings (see Anthropic docs) | All users in your organization |
| Personal | ~/.claude/skills/<skill-name>/SKILL.md |
All your projects |
| Project | .claude/skills/<skill-name>/SKILL.md |
This project only |
| Plugin | <plugin>/skills/<skill-name>/SKILL.md |
Where plugin is enabled |
When skills share the same name across levels, higher-priority locations win: enterprise > personal > project. Plugin skills use a plugin-name:skill-name namespace, so they never conflict with other levels.
Monorepo support
When you work with files in subdirectories, Claude Code automatically discovers skills from nested .claude/skills/ directories. If you are editing a file in packages/frontend/, Claude Code also looks for skills in packages/frontend/.claude/skills/. This is ideal for monorepos where packages need their own specialized skills.
Skills from additional directories
Skills defined in .claude/skills/ within directories added via --add-dir are loaded automatically and picked up by live change detection, so you can edit them during a session without restarting.
Frontmatter Reference
All frontmatter fields are optional. Only description is strongly recommended so Claude knows when to use the skill.
---
name: my-skill
description: What this skill does and when to use it
argument-hint: "[issue-number]"
disable-model-invocation: false
user-invocable: true
allowed-tools: Read, Grep, Glob
model: claude-sonnet-4-20250514
context: fork
agent: Explore
---| Field | Description |
|---|---|
name |
Display name for the skill. If omitted, uses the directory name. Lowercase letters, numbers, and hyphens only (max 64 characters). |
description |
What the skill does and when to use it. Claude uses this to decide when to load it automatically. If omitted, uses the first paragraph of content. |
argument-hint |
Hint shown during autocomplete, e.g. [issue-number] or [filename] [format]. |
disable-model-invocation |
Set to true to prevent Claude from automatically loading this skill. For manual-only workflows. Default: false. |
user-invocable |
Set to false to hide from the / menu. For background knowledge Claude should use but users should not invoke directly. Default: true. |
allowed-tools |
Tools Claude can use without asking permission when this skill is active. |
model |
Model to use when this skill runs. |
context |
Set to fork to run in an isolated subagent context. |
agent |
Which subagent type to use when context: fork is set (e.g. Explore, Plan, general-purpose, or a custom agent). |
hooks |
Hooks scoped to this skill's lifecycle. |
Automatic Invocation
This is the key difference from the old commands system: Claude can load skills automatically based on context.
Here is how it works:
- Description indexing — When a session starts, Claude reads the
descriptionfield from every available skill. These descriptions stay in context so Claude knows what is available. - Context matching — When you ask Claude something, it checks whether any skill descriptions match what you need.
- Automatic loading — If a skill matches, Claude loads the full
SKILL.mdcontent and follows its instructions.
For example, if you have a skill with this description:
description: API design patterns for this codebase. Use when writing API endpoints or reviewing API code.Then when you say "Add a new endpoint for user preferences," Claude recognizes the match and loads the skill automatically. You never need to type a slash command.
Controlling automatic invocation
Not every skill should fire automatically. Deployment workflows, destructive operations, or anything with side effects should require explicit invocation.
| Frontmatter | You Can Invoke | Claude Can Invoke | When Loaded |
|---|---|---|---|
| (default) | Yes | Yes | Description always in context; full skill loads when invoked |
disable-model-invocation: true |
Yes | No | Description not in context; loads only when you invoke |
user-invocable: false |
No | Yes | Description always in context; full skill loads when invoked |
Rule of thumb: If the skill has side effects (deploying, committing, sending messages), add disable-model-invocation: true. If the skill is background knowledge users should not invoke directly, add user-invocable: false.
Slash Command Invocation
You can always invoke a skill manually by typing /skill-name:
/explain-code src/auth/login.tsTab completion works in Claude Code — type / and start typing to see available skills and their argument-hint values.
Passing arguments
Arguments are available via the $ARGUMENTS placeholder:
---
name: fix-issue
description: Fix a GitHub issue
disable-model-invocation: true
---
Fix GitHub issue $ARGUMENTS following our coding standards.
1. Read the issue description
2. Understand the requirements
3. Implement the fix
4. Write tests
5. Create a commitRunning /fix-issue 123 gives Claude: "Fix GitHub issue 123 following our coding standards..."
If your skill does not include $ARGUMENTS, Claude Code appends ARGUMENTS: <your input> to the end automatically.
Positional arguments
Access individual arguments by position with $ARGUMENTS[N] or the shorthand $N:
---
name: migrate-component
description: Migrate a component from one framework to another
---
Migrate the $0 component from $1 to $2.
Preserve all existing behavior and tests.Running /migrate-component SearchBar React Vue replaces $0 with SearchBar, $1 with React, and $2 with Vue.
Other substitutions
| Variable | Description |
|---|---|
$ARGUMENTS |
All arguments passed when invoking the skill |
$ARGUMENTS[N] or $N |
Specific argument by 0-based index |
${CLAUDE_SESSION_ID} |
Current session ID (useful for logging) |
Built-in Skills
Claude Code ships with several built-in skills. These are available out of the box:
| Command | What It Does |
|---|---|
/commit |
Create a git commit with a well-formatted message |
/review-pr |
Review a pull request |
/init |
Initialize Claude Code in a project (creates CLAUDE.md) |
For other built-in commands like /help, /compact, /context, and /permissions, see the interactive mode documentation — those are built-in commands, not skills.
Creating Custom Skills
Step-by-step guide
1. Create the skill directory:
# Personal skill (available in all projects)
mkdir -p ~/.claude/skills/my-skill
# Project skill (available only in this project, can be committed to git)
mkdir -p .claude/skills/my-skill2. Write the SKILL.md file:
---
name: my-skill
description: Clear description of what this does and when to use it
---
Your instructions here. Be specific about:
- What Claude should do
- What output format to use
- What quality criteria to follow
- How to handle edge cases3. Test it:
# Automatic invocation — ask something that matches the description
How does the auth system work?
# Manual invocation
/my-skill src/auth/4. Iterate. The first version will not be perfect. Use the skill a few times and refine the instructions based on what Claude gets right and wrong.
Practical Examples
Code Review Skill
---
name: review
description: Thorough code review of current branch changes against main. Use when reviewing code, checking for issues, or preparing a PR.
disable-model-invocation: true
allowed-tools: Bash(git *), Read, Grep, Glob
---
Review the changes in the current branch against main.
## Steps
1. Run `git diff main...HEAD` to see all changes
2. Run `git log main..HEAD --oneline` to understand the commit history
3. For each changed file, evaluate:
- **Correctness**: Does the logic work? Are there edge cases?
- **Security**: Any OWASP top-10 issues? Hardcoded secrets?
- **Performance**: N+1 queries, unnecessary allocations, missing indexes?
- **Style**: Does it follow the conventions in CLAUDE.md?
- **Tests**: Are the changes adequately tested?
## Output format
Use this structure:
- **Summary**: 2-3 sentences on what changed and why
- **Issues**: Grouped as Critical / Major / Minor
- **Suggestions**: Improvements that are not blockers
- **Verdict**: Approve / Request Changes / Needs DiscussionUsage: /review after pushing your feature branch commits.
Deployment Checklist Skill
---
name: deploy
description: Run the deployment checklist for production releases
disable-model-invocation: true
---
Deploy $ARGUMENTS to production using this checklist:
## Pre-deploy
1. Run the full test suite — `npm test`
2. Check for lint errors — `npm run lint`
3. Verify the build — `npm run build`
4. Check for uncommitted changes — `git status`
5. Confirm we are on the correct branch
## Deploy
6. Tag the release: `git tag -a v$(date +%Y%m%d-%H%M) -m "Production release"`
7. Push the tag: `git push origin --tags`
8. Run the deploy command: `npm run deploy:production`
## Post-deploy
9. Verify the deployment succeeded (check health endpoint)
10. Run smoke tests against production
11. Report results with the tag name and deploy time
## Abort conditions
Stop immediately and report if:
- Any test fails
- There are uncommitted changes
- The build fails
- The health check fails after deployUsage: /deploy api-server to deploy a specific service.
Documentation Generator Skill
This example uses supporting files to keep the main skill focused:
.claude/skills/generate-docs/SKILL.md:
---
name: generate-docs
description: Generate API documentation for a module or file. Use when asked to document code or create API docs.
allowed-tools: Read, Grep, Glob, Bash(npx *)
---
Generate comprehensive documentation for $ARGUMENTS.
## Steps
1. Read the target file(s)
2. Identify all exported functions, classes, and types
3. For each export, document:
- Purpose (one sentence)
- Parameters with types and descriptions
- Return value
- Example usage
- Edge cases or gotchas
## Format
Use the template in [template.md](template.md) for the output structure.
## Quality checks
- Every public function must have at least one example
- Parameter types must be accurate (read the source, do not guess)
- Examples must be syntactically valid.claude/skills/generate-docs/template.md:
# Module: {module_name}
{one-paragraph description}
## Functions
### `functionName(param1, param2)`
{description}
**Parameters:**
| Name | Type | Description |
|------|------|-------------|
| param1 | string | ... |
**Returns:** `ReturnType` — {description}
**Example:**
```js
const result = functionName('hello', 42);
Usage: `/generate-docs src/utils/validation.ts`
---
## Advanced Patterns
### Injecting dynamic context
The `` !`command` `` syntax runs shell commands *before* the skill content is sent to Claude. The command output replaces the placeholder:
```yaml
---
name: pr-summary
description: Summarize changes in a pull request
context: fork
agent: Explore
allowed-tools: Bash(gh *)
---
## Pull request context
- PR diff: !`gh pr diff`
- PR comments: !`gh pr view --comments`
- Changed files: !`gh pr diff --name-only`
## Your task
Summarize this pull request: what changed, why, and any concerns.When this runs, each !`command` executes immediately and its output gets inserted into the prompt. Claude only sees the final rendered result.
Running skills in a subagent
Add context: fork to run a skill in an isolated context. The skill content becomes the prompt that drives a subagent, separate from your conversation history:
---
name: deep-research
description: Research a topic thoroughly in the codebase
context: fork
agent: Explore
---
Research $ARGUMENTS thoroughly:
1. Find relevant files using Glob and Grep
2. Read and analyze the code
3. Summarize findings with specific file referencesThe agent field determines the execution environment. Options include built-in agents (Explore, Plan, general-purpose) or any custom subagent you define in .claude/agents/. If omitted, it defaults to general-purpose.
Restricting tool access
Use allowed-tools to limit what Claude can do when a skill is active. This creates a read-only exploration mode:
---
name: safe-reader
description: Explore the codebase without making any changes
allowed-tools: Read, Grep, Glob
---
Explore and explain the code at $ARGUMENTS.
Do not modify any files.Skills vs CLAUDE.md vs Hooks
These three systems complement each other. Here is when to use which:
| Use Case | Use This | Why |
|---|---|---|
| Project conventions ("use tabs, not spaces") | CLAUDE.md | Always-on context, applies to everything |
| One-off knowledge ("our DB uses read replicas") | CLAUDE.md | Background context, not a task |
| Reusable task ("review this PR") | Skill | Structured instructions invoked on demand |
| Domain knowledge Claude should auto-apply | Skill with user-invocable: false |
Auto-loads when relevant, but not a command |
| Automated validation (lint on every file write) | Hook | Runs on events, no manual invocation |
| Pre-commit checks | Hook | Fires on tool events automatically |
| Complex workflow with supporting files | Skill | Directory structure supports templates, scripts, examples |
Quick test: If you are writing rules Claude should always follow, put them in CLAUDE.md. If you are writing instructions Claude should follow for a specific task, make it a skill. If you want something to happen automatically on an event, make it a hook.
Tips for Writing Great Skills
Start with the outcome. What should Claude have produced when the skill completes? State it clearly at the top.
Include quality criteria. "Write a good commit message" is vague. Specify the format, character limits, and what "good" means in your context.
Specify the output format. Should Claude produce a list? A table? Code changes? A report? Silence (just make the changes)?
Handle edge cases. What should happen if there is nothing staged? If the tests fail? If the file does not exist?
Write accurate descriptions. The description field is how Claude decides whether to load a skill automatically. Include the keywords and situations where the skill applies. Be specific enough that it does not trigger on unrelated requests.
Use disable-model-invocation for side effects. Any skill that deploys, commits, sends messages, or modifies external systems should require explicit invocation.
Sharing Skills
Skills can be distributed at different scopes:
- Project skills: Commit
.claude/skills/to version control. Everyone on the team gets them. - Plugins: Create a
skills/directory in your plugin for distribution. - Managed settings: Deploy organization-wide through enterprise managed settings.
Troubleshooting
Skill not triggering automatically?
- Check that the
descriptionincludes keywords users would naturally say - Verify the skill shows up when you ask "What skills are available?"
- Try invoking it directly with
/skill-nameto confirm it works - Make sure
disable-model-invocationis not set totrue
Skill triggering too often?
- Make the
descriptionmore specific - Add
disable-model-invocation: truefor manual-only invocation
Claude does not see all your skills?
- Skill descriptions have a context budget (2% of the context window, ~16,000 characters fallback). If you have many skills, some may be excluded.
- Run
/contextto check for a warning about excluded skills. - Set the
SLASH_COMMAND_TOOL_CHAR_BUDGETenvironment variable to override the limit.
Practical Exercise
Build three skills for your actual workflow:
- A task skill — Something you do repeatedly (deploys, releases, migrations). Use
disable-model-invocation: trueso it only fires on your command. - A reference skill — Domain knowledge Claude should apply automatically (API conventions, code style beyond what is in CLAUDE.md). Use
user-invocable: falseso Claude loads it when relevant. - A skill with supporting files — A documentation generator or report builder that uses a template file in the skill directory.
Use each skill at least three times and refine the instructions based on the results.