Skills — Reusable Prompt Templates
You have written the same prompt a dozen times: "Review this code for security issues and performance bottlenecks, then suggest fixes." You have typed out deployment checklists, commit message formats, and review rubrics over and over. Each time, you rephrase slightly, forget a step, or lose the version that worked best.
Skills solve this. A skill is a reusable prompt template stored as a SKILL.md file. Define it once, invoke it with a slash command forever. Think of skills as functions for your prompts -- they accept arguments, inject dynamic context, and execute consistently every time.
Learning Objectives
- Understand what skills are and how they extend Claude Code's capabilities
- Create custom SKILL.md files with proper frontmatter configuration
- Control invocation behavior (user-invocable, agent-invocable, or both)
- Use
$ARGUMENTSand dynamic context injection with!commands - Distinguish between reference skills and task skills and know when to use each
What Are Skills?
A skill is a markdown file that contains instructions for Claude. When invoked, those instructions get injected into Claude's context, shaping how it responds. Skills appear as slash commands in Claude Code -- type / and you will see your skills listed alongside built-in commands.
The key insight: skills are not code. They are structured prompts. A skill that reviews pull requests does not contain review logic -- it contains instructions that tell Claude how to review pull requests, what to look for, and how to format the output.
Skills follow the Agent Skills open standard, which means they work across multiple AI tools. Claude Code extends the standard with additional features like invocation control, subagent execution, and dynamic context injection.
Commands and Skills Are Unified
If you have used .claude/commands/ files before, those still work. Skills in .claude/skills/ add optional features: a directory for supporting files, frontmatter to control invocation, and the ability for Claude to load them automatically when relevant. If a skill and a command share the same name, the skill takes precedence.
Skill File Structure
Every skill lives in a directory with a SKILL.md file as the entrypoint. The file has two parts: YAML frontmatter that configures behavior, and markdown content with the actual instructions.
---
name: review-code
description: Reviews code for bugs, security issues, and performance problems
---
When reviewing code, check for:
1. **Security vulnerabilities**: SQL injection, XSS, auth bypass
2. **Performance issues**: N+1 queries, unnecessary re-renders, memory leaks
3. **Code quality**: Naming conventions, function length, DRY violations
Format your review as a numbered list of findings, each with:
- Severity (critical / warning / suggestion)
- File and line reference
- Description of the issue
- Suggested fixSkills can also include supporting files alongside SKILL.md:
review-code/
├── SKILL.md # Main instructions (required)
├── checklist.md # Detailed review checklist
├── examples/
│ └── sample.md # Example review output
└── scripts/
└── lint-check.sh # Script Claude can execute
Reference supporting files from your SKILL.md so Claude knows when to load them. Keep SKILL.md under 500 lines and move detailed reference material into separate files.
Where Skills Live
Where you store a skill determines its scope:
| Location | Path | Applies To |
|---|---|---|
| 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 |
| Enterprise | Managed settings | All users in your organization |
When skills share the same name, 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
Claude Code automatically discovers skills from nested .claude/skills/ directories. If you are editing a file in packages/frontend/, Claude also looks for skills in packages/frontend/.claude/skills/. This makes monorepo setups clean -- each package can define its own skills.
Frontmatter Reference
Frontmatter fields between --- markers configure skill behavior. All fields are optional, but 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: "[filename] [format]"
disable-model-invocation: true
user-invocable: true
allowed-tools: Read, Grep, Glob
context: fork
---| Field | Description |
|---|---|
name | Display name and slash command. Defaults to directory name. Lowercase, numbers, hyphens only (max 64 chars). |
description | What the skill does. Claude uses this to decide when to auto-load it. |
argument-hint | Hint shown during autocomplete (e.g., [issue-number]). |
disable-model-invocation | Set true to prevent Claude from auto-loading. User must invoke with /name. |
user-invocable | Set false to hide from the / menu. Only Claude can invoke. |
allowed-tools | Tools Claude can use without permission prompts when this skill is active. |
context | Set to fork to run in an isolated subagent context. |
agent | Which subagent type to use when context: fork is set. |
Controlling Who Invokes a Skill
By default, both you and Claude can invoke any skill. You type /skill-name to invoke directly, and Claude loads it automatically when relevant. Two frontmatter fields let you restrict this:
User-Only Skills (disable-model-invocation)
Set disable-model-invocation: true for workflows with side effects or where you want to control timing:
---
name: deploy
description: Deploy the application to production
disable-model-invocation: true
---
Deploy $ARGUMENTS to production:
1. Run the test suite
2. Build the application
3. Push to the deployment target
4. Verify the deployment succeededYou do not want Claude deciding to deploy because your code looks ready. Deployments, commits, notifications -- anything with side effects should be user-only.
Claude-Only Skills (user-invocable: false)
Set user-invocable: false for background knowledge that is not actionable as a command:
---
name: legacy-api-context
description: Architecture and quirks of the legacy payment API
user-invocable: false
---
The legacy payment API uses SOAP over HTTP. Key quirks:
- All amounts are in cents, not dollars
- The `processPayment` endpoint returns 200 even on failure
- Check the `statusCode` field in the response body
- Retry logic must handle idempotency keysClaude loads this automatically when you work on payment-related code, but /legacy-api-context does not appear in your slash command menu because it is not a meaningful action for you to take manually.
Invocation Summary
| 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 | Not in context until you invoke |
user-invocable: false | No | Yes | Description always in context; full skill loads when relevant |
Arguments with $ARGUMENTS
Skills accept arguments passed after the slash command. Use the $ARGUMENTS placeholder in your template to control where they appear.
---
name: fix-issue
description: Fix a GitHub issue by number
disable-model-invocation: true
argument-hint: "[issue-number]"
---
Fix GitHub issue #$ARGUMENTS following our coding standards.
1. Read the issue description using `gh issue view $ARGUMENTS`
2. Understand the requirements
3. Implement the fix
4. Write tests covering the fix
5. Create a commit referencing the issueRunning /fix-issue 247 replaces every $ARGUMENTS with 247. If a skill does not include $ARGUMENTS, Claude Code appends ARGUMENTS: <your input> to the end of the content so Claude still sees what you typed.
Positional Arguments
For skills that take multiple inputs, use $ARGUMENTS[N] (zero-indexed) or the shorthand $N:
---
name: migrate-component
description: Migrate a component from one framework to another
argument-hint: "[component] [from-framework] [to-framework]"
---
Migrate the `$0` component from $1 to $2.
Preserve all existing behavior and tests. Follow $2 best practices
for component structure, state management, and lifecycle hooks.Running /migrate-component SearchBar React Vue produces:
Migrate the
SearchBarcomponent from React to Vue.
Dynamic Context with ! Commands
The ! command syntax runs shell commands before the skill content reaches Claude. The command output replaces the placeholder, so Claude receives real data instead of a command string.
---
name: pr-summary
description: Summarize changes in the current pull request
context: fork
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. Include:
1. What changed and why
2. Risk assessment (what could break)
3. Suggested reviewers based on file ownershipWhen this skill runs, each !`command` executes immediately. Claude never sees the commands -- only their output. This is preprocessing, not something Claude executes at runtime.
Dynamic Context Is Preprocessing
The ! commands run at invocation time, before Claude sees the prompt. They are not interactive. If a command fails or produces no output, that section will be empty in the final prompt. Test your commands independently first.
Reference Skills vs. Task Skills
Thinking about how you want a skill invoked helps guide what to put in it.
Reference Skills
Reference skills add knowledge that Claude applies to your current work. They contain conventions, patterns, style guides, or domain knowledge. Claude loads them automatically when relevant and uses them alongside your conversation.
---
name: api-conventions
description: REST API design patterns and conventions for this codebase
---
When writing API endpoints in this project:
- Use RESTful naming: plural nouns for collections (`/users`), not verbs
- Return consistent error format: `{ "error": { "code": "...", "message": "..." } }`
- Include request validation with Zod schemas
- All responses include `X-Request-Id` header
- Pagination uses cursor-based format: `?cursor=abc&limit=20`
- Rate limiting headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`Task Skills
Task skills give Claude step-by-step instructions for a specific action. These are workflows you invoke deliberately with /skill-name. Add disable-model-invocation: true to prevent Claude from triggering them automatically.
---
name: release-notes
description: Generate release notes from recent commits
disable-model-invocation: true
argument-hint: "[version-tag]"
---
Generate release notes for version $ARGUMENTS:
1. Get commits since last tag: !`git log $(git describe --tags --abbrev=0)..HEAD --oneline`
2. Categorize each commit:
- **Features**: New functionality (feat: commits)
- **Fixes**: Bug fixes (fix: commits)
- **Breaking**: Breaking changes (BREAKING CHANGE in body)
- **Other**: Refactors, docs, chores
3. Write a human-readable summary for each category
4. Include migration notes for any breaking changes
5. Output in markdown format suitable for a GitHub releaseThe distinction is not rigid -- some skills blend both. But thinking through the intent helps you set the right frontmatter and write effective instructions.
Creating a Custom Skill: Code Review
Let's walk through creating a practical skill from scratch. This /review skill reads changed files, checks for common issues, and generates a structured review.
Create the skill directory
mkdir -p .claude/skills/reviewWrite the SKILL.md file
Create .claude/skills/review/SKILL.md:
---
name: review
description: Review staged or recent changes for bugs, security issues, and style problems
disable-model-invocation: true
argument-hint: "[file-or-branch (optional)]"
allowed-tools: Read, Grep, Glob, Bash(git *)
---
## Context
Current branch: !`git branch --show-current`
Recent commits: !`git log --oneline -5`
Staged changes: !`git diff --cached --stat`
Unstaged changes: !`git diff --stat`
## Review instructions
Review the changes shown above. If $ARGUMENTS specifies a file, focus on
that file. Otherwise review all staged and unstaged changes.
For each finding, report:
- **Severity**: critical / warning / suggestion
- **Location**: file path and line number
- **Issue**: what is wrong and why it matters
- **Fix**: concrete suggestion with code
### Check for these categories:
**Security**
- Input validation and sanitization
- Authentication and authorization gaps
- Secrets or credentials in code
- SQL injection, XSS, CSRF vulnerabilities
**Bugs**
- Off-by-one errors, null references
- Race conditions, missing error handling
- Incorrect type usage
**Performance**
- N+1 queries, unnecessary iterations
- Missing memoization or caching opportunities
- Large bundle size additions
**Style**
- Naming conventions, function length
- DRY violations, dead code
- Missing or misleading comments
## Output format
Start with a one-line summary (e.g., "3 critical, 5 warnings, 2 suggestions").
Then list findings grouped by severity, most critical first.
End with an overall assessment: approve, request changes, or needs discussion.Test the skill
Invoke it directly after making some changes:
/review
Or target a specific file:
/review src/auth/login.ts
Claude receives the dynamically injected git context (branch, recent commits, diff stats) plus your full review instructions, and produces a structured code review.
Restricting Tool Access
Use allowed-tools to limit what Claude can do when a skill is active. This is useful for creating read-only exploration skills or restricting side effects:
---
name: explore
description: Explore the codebase without making changes
allowed-tools: Read, Grep, Glob
---
Explore the codebase to answer the following question: $ARGUMENTS
Read files, search for patterns, and trace through the code.
Do not modify any files. Report your findings with file references.When this skill is active, Claude can use Read, Grep, and Glob without permission prompts -- but cannot use Bash, Write, or Edit.
Running Skills in a Subagent
Add context: fork to run a skill in an isolated context. The skill content becomes the prompt for a subagent that has no access to your conversation history. Results are summarized and returned to your main session.
---
name: deep-research
description: Research a topic thoroughly using codebase exploration
context: fork
agent: Explore
---
Research $ARGUMENTS thoroughly:
1. Find relevant files using Glob and Grep
2. Read and analyze the code
3. Trace through function calls and data flow
4. Summarize findings with specific file references and line numbersThis keeps your main context clean. The subagent's exploration -- all the file reads and searches -- stays in its own context window and does not pollute your working session.
When to Fork
Use context: fork for research, analysis, and exploration skills. Keep skills inline (no context: fork) when they provide guidelines or conventions that Claude needs alongside your conversation context.
Create a Reference Skill and a Task Skill
intermediate20 minBuild two custom skills for a project you work on:
Skill 1: Coding Conventions (Reference)
Create a reference skill at .claude/skills/conventions/SKILL.md that encodes your team's coding standards. It should:
- Have a descriptive
descriptionso Claude loads it automatically when writing code - Keep
user-invocableas default (both you and Claude can use it) - Cover naming conventions, file structure, error handling patterns, and import ordering
- Be specific to your stack (e.g., React conventions, Python conventions, Go conventions)
Skill 2: Release Notes Generator (Task)
Create a task skill at .claude/skills/changelog/SKILL.md that generates release notes. It should:
- Set
disable-model-invocation: true(user-only) - Accept a version tag as
$ARGUMENTS - Use
!`git log ...`to inject recent commits dynamically - Categorize commits into features, fixes, and breaking changes
- Output formatted markdown suitable for a
CHANGELOG.mdentry
Verification:
- Run
claudeand type/to see your skills in the autocomplete menu - Ask Claude "What coding conventions should I follow?" and verify it loads your conventions skill automatically
- Run
/changelog v2.1.0and verify it generates structured release notes from your git history
Bonus: Add an argument-hint to the changelog skill so the autocomplete shows [version-tag] as a placeholder.
Key Takeaway
- Skills are reusable prompt templates stored as
SKILL.mdfiles in.claude/skills/directories - Frontmatter controls invocation:
disable-model-invocation: truefor user-only,user-invocable: falsefor Claude-only - Use
$ARGUMENTS(or$0,$1,$2) to accept dynamic input from slash commands - Use
!`command`syntax to inject shell command output as preprocessing before Claude sees the prompt - Reference skills provide guidelines Claude applies automatically; task skills are workflows you invoke deliberately
- Add
context: forkto run skills in isolated subagents, keeping your main context clean - Store personal skills in
~/.claude/skills/and project skills in.claude/skills/-- commit project skills to version control for your team
Next Steps
You now know how to package your best prompts into reusable, shareable skills. In the next lesson, we will explore Subagents — Specialized AI Workers — how to use built-in Explore, Plan, and general-purpose subagents, create custom agents with focused prompts and restricted tool access, and apply subagent patterns for parallel research and cost optimization.
Resources:
- Official Skills documentation
- Agent Skills open standard
/help skillsfor quick reference in Claude Code