How to Build a Custom Claude Code Skill (Step-by-Step)
A Claude Code skill is a markdown file that gives Claude a specialized, repeatable workflow — a named procedure Claude can follow on demand or when triggered by a specific condition. Skills let you encode your team's runbooks, deployment checklists, and code review procedures into Claude once and reuse them indefinitely, without re-explaining them every session. For the broader Claude Code feature set, see the Claude Code Complete Guide.
This guide covers the full authoring cycle: file structure, triggers, bash preambles, interactive prompts, and a complete worked example.
What a Skill Is (and Isn't)
A skill is a .md file that lives in ~/.claude/skills/ (user-level, available in every project) or .claude/skills/ (project-level, checked into your repo). When Claude encounters a matching trigger — a slash command, a keyword in your message, or a condition you define — it loads the skill's instructions and follows them.
Skills are different from:
- CLAUDE.md — project context loaded automatically at session start; not invoked on demand
- MCP tools — external process integrations; skills are pure instructions with no external runtime
- Custom slash commands — slash commands can invoke skills, but a skill contains the actual procedure
The SKILL.md File Structure
Every skill file follows the same shape:
---
name: skill-name
description: "One-line summary of what this skill does"
trigger: /slash-command-name
---
# Skill Name
Brief description of when and why to use this skill.
## Preamble
```bash
# Optional: shell commands to run before Claude starts
Instructions
- Step one
- Step two
- Step three
AskUserQuestion
[Optional: questions to ask the user during the workflow]
### Frontmatter Fields
| Field | Required | Purpose |
|---|---|---|
| `name` | Yes | Identifier used internally |
| `description` | Yes | Shown in `/skills` list |
| `trigger` | Yes | What invokes the skill |
The `trigger` field accepts:
- A slash command: `/deploy-check`
- A keyword phrase: `"when I say 'run checks'"`
- A condition: `"after completing a code change"` (auto-invoke)
---
## Triggers: When Claude Auto-Invokes a Skill
Skills can be invoked two ways:
**Explicit (slash command):** The user types `/skill-name`. Claude loads the skill and follows its instructions immediately.
**Automatic (keyword or condition trigger):** Claude detects the trigger condition during a normal conversation. For example:
```yaml
trigger: "whenever the user asks to deploy or push to production"
With this trigger, Claude auto-invokes the skill if you say "let's push this" or "deploy to prod" — without needing to type a slash command.
Auto-invocation triggers are powerful but should be specific. Overly broad triggers (like "whenever Claude completes a task") will fire too often and slow down normal work.
Writing a Bash Preamble
The preamble is a bash block that Claude runs before executing the rest of the skill instructions. It serves two purposes:
- Gather context — collect current state (git status, test results, env variables) so Claude has accurate data before making decisions
- Fail fast — exit early with a clear error if prerequisites aren't met
Example preamble that checks prerequisites:
# Check we're in a git repo
git rev-parse --git-dir > /dev/null 2>&1 || { echo "ERROR: Not a git repository."; exit 1; }
# Capture current state
echo "=== Current Branch ==="
git branch --show-current
echo "=== Uncommitted Changes ==="
git status --short
echo "=== Last 5 Commits ==="
git log --oneline -5
echo "=== Test Status ==="
npm test --passWithNoTests 2>&1 | tail -5
The preamble output is injected into Claude's context before the skill instructions run. Claude reads it and adjusts its recommendations accordingly — it won't suggest pushing if tests are failing, for example.
Key rules for preambles:
- Keep each command fast (under 5 seconds total)
- Use
|| { echo "ERROR: ..."; exit 1; }for hard prerequisites - Print section headers (
=== ... ===) so Claude can parse the output easily - Avoid side effects in the preamble — save mutations for the instructions phase
The AskUserQuestion Pattern
Skills often need input before proceeding. The AskUserQuestion section lets you define structured questions Claude will ask the user during the workflow.
## AskUserQuestion
Before proceeding, ask the user:
1. **Target environment:** "Are you deploying to staging or production?"
- If staging: continue with standard checks
- If production: require explicit confirmation with the string "CONFIRM PROD"
2. **Rollback plan:** "Do you have a rollback plan in place?"
- If no: remind them to create one before continuing
Claude will pause at the appropriate point in the workflow, ask the question, and branch based on the answer. This turns a static checklist into an interactive decision tree.
You can also specify that Claude should stop the workflow entirely if a blocking condition is met:
If the user cannot confirm a rollback plan, stop the workflow and output:
"Deploy cancelled. Please document your rollback procedure before deploying."
Complete Worked Example: The /deploy-check Skill
Here is a complete skill that checks git status, runs tests, verifies environment config, and asks for confirmation before deploying.
File location: .claude/skills/deploy-check.md
---
name: deploy-check
description: "Pre-deploy checklist: git status, tests, env config, and deployment confirmation"
trigger: /deploy-check
---
# Deploy Check
Run this skill before any deployment to staging or production. It validates that
your working tree is clean, tests pass, required environment variables are set,
and gets explicit confirmation before handing off to the deploy script.
## Preamble
```bash
echo "=== Git Status ==="
git status --short
echo "=== Current Branch ==="
git branch --show-current
echo "=== Unpushed Commits ==="
git log @{u}.. --oneline 2>/dev/null || echo "(no upstream configured)"
echo "=== Test Run ==="
npm test 2>&1 | tail -20
echo "=== Required Env Vars ==="
for var in DATABASE_URL REDIS_URL API_SECRET; do
if [ -z "${!var}" ]; then
echo "MISSING: $var"
else
echo "OK: $var"
fi
done
Instructions
-
Review the preamble output. If any of the following are true, STOP and report the issue:
- There are uncommitted changes (dirty working tree)
- Any tests failed
- Any required env vars are MISSING
-
If all checks pass, report a green summary:
✓ Working tree clean ✓ All tests passing ✓ All required env vars present Branch: [branch name] Unpushed commits: [N commits] -
Ask the user the AskUserQuestion questions.
-
If the user confirms, output the deploy command to run:
npm run deployDo NOT run the deploy command automatically — output it for the user to execute.
AskUserQuestion
Before outputting the deploy command, ask:
-
Deployment target: "Deploying to staging or production?"
- If production: require the user to type "CONFIRM PRODUCTION DEPLOY" exactly
- If they type anything else, do not proceed
-
Changelog: "Have you updated the changelog or release notes?"
- If no: remind them and ask if they want to proceed anyway
- Their choice: respect it but log a warning in the output
Save this file, then in any Claude Code session type `/deploy-check`. Claude will run the preamble, evaluate the results, ask the two questions, and gate the deploy command on explicit confirmation.
---
## How to Share Skills with Your Team
**Option 1: Commit to the repo**
Place skill files in `.claude/skills/` at your project root and commit them. Every team member who checks out the repo gets the skills automatically when they open Claude Code in that directory.
**Option 2: Shared dotfiles / internal package**
For organization-wide skills, maintain a private `dotfiles` or `claude-skills` repo. Have team members symlink or copy the skills folder to `~/.claude/skills/`.
**Option 3: Claude Code settings sync**
If your organization uses Claude Code with a shared settings profile, skill files can be distributed via the same mechanism as `claude_desktop_config.json`.
**Naming conventions for team skills:**
- Prefix with a namespace: `/[team]-deploy-check`, `/[team]-review`
- Use verb-first naming: `deploy-check`, `create-pr`, `review-migration`
- Document the `description` field clearly — it shows up in `/skills` for all teammates
**Version-controlling skills:**
Treat skill files like code. Use descriptive commit messages when you update a skill ("update deploy-check to require CONFIRM PRODUCTION string"), and review changes in PRs so teammates see what behavioral changes they're getting.
---
## FAQ
**Q: What's the difference between a skill trigger and a CLAUDE.md instruction?**
CLAUDE.md instructions are always active — they set standing behavior for every session. Skill triggers are invoked on demand or when a specific condition occurs. Use CLAUDE.md for persistent rules ("always use TypeScript strict mode"), skills for discrete procedures ("when I ask to deploy, run this checklist").
**Q: Can a skill call another skill?**
Not directly — skills don't have an explicit import mechanism. However, you can reference another skill's procedure in your instructions: "After completing these steps, follow the steps in the `create-pr` skill." Claude will look up the referenced skill if it's available.
**Q: How long can a skill file be?**
There's no hard limit, but long skills are harder to maintain and harder for Claude to follow precisely. If a skill exceeds ~200 lines, split it into focused sub-skills. Each skill should do one thing well.
**Q: Can I use AskUserQuestion to collect sensitive input like passwords?**
Avoid it. Passwords entered into Claude Code sessions can appear in logs or session history. Use env vars for secrets, not interactive prompts.
**Q: Do skills work in Claude Desktop as well as Claude Code?**
Skills are a Claude Code feature. Claude Desktop supports some CLAUDE.md-style instructions but does not currently have the same skill invocation and bash preamble system. For details on CLAUDE.md patterns that complement skills, see [How to Write Effective CLAUDE.md Files](/claude-md-effective-patterns).
---
## Sources
- Claude Code documentation — skills: [docs.anthropic.com/claude-code/skills](https://docs.anthropic.com/claude-code/skills)
- Claude Code changelog: [docs.anthropic.com/claude-code/changelog](https://docs.anthropic.com/claude-code/changelog)
- CLAUDE.md reference: [docs.anthropic.com/claude-code/memory](https://docs.anthropic.com/claude-code/memory)
- Community skills repository: [github.com/anthropics/claude-code-skills](https://github.com/anthropics/claude-code-skills)
---
## Take It Further
**[Claude Code Power Prompts 300](https://shoutfirst.gumroad.com/l/agfda?utm_source=claudeguide&utm_medium=article&utm_campaign=how-to-build-custom-claude-code-skill)** — 300 battle-tested prompts for Claude Code, organized by use case. Copy, paste, ship.
40 slash command templates. Token-optimized variants. JSONL file for direct import. Tested in production sessions.
[→ Get Claude Code Power Prompts 300 — $29](https://shoutfirst.gumroad.com/l/agfda?utm_source=claudeguide&utm_medium=article&utm_campaign=how-to-build-custom-claude-code-skill)
*30-day money-back guarantee. Instant download.*