Skills
Skills are the unified extension system in Claude Code, following the open Agent Skills standard (agentskills.io). They replace the older "commands" system and serve a dual purpose: they are both reusable knowledge patterns that Claude auto-discovers when relevant, and user-invocable slash commands that developers trigger explicitly with /<name>. A single skill can serve both roles, or specialize in one.
Each skill lives in a directory under .claude/skills/ with a SKILL.md entrypoint file. The directory-based structure is intentional — a skill can bundle supporting files (templates, schemas, reference docs) alongside its instructions, keeping everything self-contained and portable.
Claude Code ships with five bundled skills that are available in every project without any configuration:
| Icon | Skill | Description |
|---|---|---|
| 📦 | /batch | Process multiple files or operations in a single pass. |
| 🔌 | /claude-api | Generate code that calls the Anthropic API. |
| 🐛 | /debug | Systematic debugging workflow with root cause analysis. |
| 🔄 | /loop | Iterative refinement loop — repeat until quality criteria met. |
| ✂️ | /simplify | Reduce complexity — fewer lines, clearer logic, less indirection. |
These bundled skills demonstrate the patterns you should follow when building your own. They use frontmatter fields, $ARGUMENTS substitution, and context forking — all features available to custom skills.
A SKILL.md file has YAML frontmatter that controls how and when the skill activates, followed by markdown instructions that Claude follows when the skill is invoked:
.claude/skills/tdd-workflow/SKILL.md
---
name: tdd-workflow
description: "Test-Driven Development workflow: Red → Green → Refactor"
user-invocable: true
argument-hint: "<file-path>"
allowed-tools:
- Read
- Edit
- Write
- Bash
---
Follow the TDD workflow strictly:
## Step 1: Red
Write a failing test first. Run it to confirm it fails.
Command: `npm test -- --testPathPattern=$ARGUMENTS`
## Step 2: Green
Write the minimum code to make the test pass. No more.
## Step 3: Refactor
Clean up both test and implementation. Run tests again.
## Rules
- NEVER write implementation before the test exists
- Each test should test ONE behavior
- Test file must exist before source fileKey frontmatter fields control the skill's behavior:
| Field | Purpose | Example |
|---|---|---|
name | Skill identifier (used as /name for slash commands) | tdd-workflow |
description | When to trigger — Claude uses this for auto-discovery | "TDD workflow for test-first development" |
user-invocable | If true, appears as a slash command (/tdd-workflow) | true | false |
argument-hint | Hint text shown after /name in autocomplete | "<file-path>" |
allowed-tools | Restrict which tools the skill can use | [Read, Edit, Bash] |
model | Override the model for this skill execution | haiku, sonnet, opus |
context: fork | Run the skill in an isolated context (like a sub-agent) | fork |
disable-model-invocation | If true, skill only provides context — no AI reasoning | true |
$ARGUMENTS / $1 $2 | Special variables — replaced with user input after /name | "src/routes/tasks.js" |
Skills activate in two distinct ways, and understanding the difference is key to designing effective skills:
| Auto-Discovered (Passive) | User-Invoked (Active) |
|---|---|
Claude reads the skill's description field | Developer types /skill-name to trigger explicitly |
| When working context matches, skill loads automatically | user-invocable: true must be set in frontmatter |
| No user action required — seamless | $ARGUMENTS captures text after the command name |
| Good for: conventions, standards, patterns | Good for: workflows, multi-step processes, reports |
| Example: OWASP checklist loads when editing auth code | Example: /tdd-workflow src/routes/tasks.js |
Many skills work in both modes. A tdd-workflow skill can auto-discover when Claude notices you are writing tests, and also be explicitly invoked with /tdd-workflow when you want to force the workflow for a specific file.
Skills can inject dynamic information into their instructions with the !command! syntax — for example, embedding !git diff --stat! inside a review skill runs the command at skill-load time and substitutes the output inline before Claude reasons over it. This makes skills adaptive to the current project state. Bangs run with your shell permissions and are not sandboxed — only use trusted commands, never user-controlled input.
Skills are directory-based packages, not just prompt files. The SKILL.md is the entrypoint, but the directory can contain anything the skill needs — scripts, templates, reference documents, schemas, example files:
<repo root>/
└── .claude/
└── skills/
└── generate-api/
├── SKILL.md # Entrypoint — instructions + frontmatter
├── route-template.js # Template Claude uses as a starting point
├── openapi-schema.yaml # Reference schema Claude checks against
├── validate.sh # Script invoked via !bash validate.sh!
└── examples/
├── good-route.js # Well-structured route
└── bad-route.js # Anti-pattern for Claude to avoidClaude can read any file in the skill directory. This means you can package complex workflows — a code generator with templates, a review checklist with reference examples, a migration tool with schema definitions — as self-contained, portable units. Copy the directory to another project and the skill works.
This is what makes skills more powerful than just a well-crafted prompt. A prompt is instructions. A skill is instructions plus reference materials plus scripts plus templates — everything Claude needs to execute a workflow reliably.
Skills can live in three places, and the location determines who gets them:
| Location | Scope | Use for |
|---|---|---|
.claude/skills/ (repo root) | Team-shared, committed to git | Project-specific workflows — /validate-route referencing this API's conventions, /design-review against this project's ADRs |
~/.claude/skills/ | Personal, machine-global | Your individual habits across every project — preferred commit-message style, personal explainer formats |
| Bundled (ship with Claude Code) | Available everywhere, no setup | The five shown at the top of this page — /batch, /claude-api, /debug, /loop, /simplify |
Rule of thumb: if another teammate on this repo would want the same slash command, commit it under .claude/skills/. If it is idiosyncratic to how you personally work, put it in ~/.claude/skills/. All TRY IT exercises in this workshop create project-level skills because they reference project-specific standards — making them personal would mean duplicating those standards for every project you touch.
The EPCC Workflow Plugin is an open-source collection of skills for a full development workflow:
| Skill | Purpose |
|---|---|
/prd | Generate a Product Requirements Document |
/trd | Generate a Technical Requirements Document |
/epcc-explore | Map the codebase — code archaeologist |
/epcc-plan | Design an implementation plan |
/epcc-code | Implement with auto-validation |
/epcc-commit | Run tests and commit |
/epcc-resume | Resume interrupted work |
Additional skill libraries:
- mattpocock/skills — Small, composable engineering and productivity skills built for practical software-development workflows.
- addyosmani/agent-skills — Production-grade skills that encode development workflows, quality gates, and engineering best practices across the software lifecycle.
Browse the source — each .md file is a skill you can read to see how production teams structure their workflow prompts. In the SDLC phases of this workshop, you will build your own skills (/validate-spec, /design-review, /self-review) following the same patterns.
Build a skill that validates a specific route file when invoked, demonstrating the $ARGUMENTS variable and dynamic context features.
Step 1 — Create the skill: Create the skill directory and SKILL.md:
Run in terminal:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir -p .claude/skills/validate-route && cat > .claude/skills/validate-route/SKILL.md << 'SKILLEOF'
---
name: validate-route
description: "Validate an API route file against project conventions"
user-invocable: true
argument-hint: "<route-file-path>"
---
Validate the route file: $ARGUMENTS
Check against these standards:
1. All handlers validate input before processing
2. Error responses use { error: "message" } format
3. Correct HTTP status codes (201 create, 204 delete)
4. No direct file I/O — must use store.js functions
5. All async operations have error handling
Current project test status:
!npm test -- --watchAll=false 2>&1 | tail -5!
SKILLEOFObserve: The skill is now available as /validate-route. The $ARGUMENTS variable will be replaced with whatever file path the developer specifies.
Step 2 — Start Claude Code: Start a Claude Code session:
Run in terminal:
1
claudeStep 3 — Test the skill: Invoke the skill:
Tell Claude:
/validate-route src/routes/tasks.jsObserve: Claude loads the skill, replaces $ARGUMENTS with src/routes/tasks.js, executes the npm test command for dynamic context, and then validates the route file against the listed standards. Skills bridge the gap between reusable conventions (auto-discovered) and team workflows (user-invoked) — the $ARGUMENTS and !command! features make them dynamic and context-aware, far more powerful than static documentation.
You may have noticed that the validate-route skill contains API standards (error format, status codes, store.js usage) that also appear in CLAUDE.md, @imported docs, and .claude/rules/. This overlap is intentional — each location serves a different purpose based on when Claude needs the information:
| Location | When It Loads | Use For | Context Cost |
|---|---|---|---|
CLAUDE.md / @imports | Every session, always in context | Things Claude should know no matter what it is doing — project overview, key commands, universal conventions | Always paid |
.claude/rules/ with globs | When Claude touches matching files | Standards for a category of files — "when editing route files, always validate input" | Paid only when relevant files are open |
| Skills | Only when invoked or auto-discovered | Active workflows that produce output — "validate this file against our checklist and report findings" | Zero until invoked |
The key distinction: rules are passive context — Claude knows about them while working on matching files (progressive disclosure). A skill is an active workflow that uses standards to produce a structured output. The validate-route skill is not just "here are our API standards" — it is "run this checklist against a specific file and tell me what is wrong."
The anti-pattern is putting standards only in a skill. Then Claude would not know about them during normal coding — it would only apply them when you explicitly invoke the validation. You want the knowledge ambient (.claude/rules/ with globs) and the workflow on-demand (skills).