Claude Code Skills: How to Build Custom Slash Commands
Last updated: April 15, 2026
Claude Code Skills
Quick answer
Skills are custom slash commands for Claude Code. A skill is a markdown file with optional YAML frontmatter stored at ~/.claude/skills/ for personal skills or .claude/skills/ for team skills. Invoke a skill in any prompt by typing /skill-name. Skills are perfect for repeatable workflows that you want to trigger on demand rather than run every session.
What a skill actually is
A skill is a markdown prompt template. When you type /my-skill in a session, Claude Code reads the file, substitutes any arguments, and injects the result into the conversation as if you had typed the prompt by hand.
This matters because it means skills are pure prompt engineering. Anything you can say in a normal prompt you can save as a skill. The file format is plain markdown with a short optional header.
File locations
Claude Code loads skills from two paths:
~/.claude/skills/: personal skills across every project..claude/skills/: project-level skills, committed to the repo so everyone on the team gets them.
If a skill name exists in both, the project version wins. A skill named commit.md in the project folder overrides your personal commit.md when you are working in that repo.
Invoking a skill
Type / at the start of a prompt to see the completion menu. All built-in commands and all loaded skills appear in the same list, sorted alphabetically.
/commit
The skill body is sent to Claude as your next prompt, preceded by any arguments you passed:
/commit fix login race condition
Arguments appear after the skill name, space-separated.
Skill file format
A skill file has two parts: an optional frontmatter block and a markdown body.
---
name: commit
description: Write a conventional commit for staged changes
arguments: [scope, message]
---
Run `git diff --cached` and write a conventional commit message.
Scope: $1
Short message: $2
Output only the commit command, no explanation.
Frontmatter fields:
name: overrides the filename as the slash command name.description: shown in the/completion menu.arguments: a list of named positional arguments (documentation only, not enforced).
None of the frontmatter is required. A bare markdown file in ~/.claude/skills/review.md becomes /review automatically.
Passing arguments
Arguments are substituted into the skill body using positional or named placeholders.
Positional: $1, $2, $3, and so on. $@ expands to all arguments joined with spaces.
Refactor the function named $1 in file $2 to use async/await.
Named arguments use the syntax $ARG_NAME and are filled in order from the command line:
Open the PR for $BRANCH with reviewers $REVIEWERS.
Call with: /pr feat/login ayush,jane. $BRANCH becomes feat/login and $REVIEWERS becomes ayush,jane.
If the caller forgets an argument, the literal placeholder string passes through. Validate argument presence in the skill body:
If $1 is empty, ask me for the function name before proceeding.
Skills vs CLAUDE.md instructions
The distinction is about when the instruction applies:
- CLAUDE.md: injected into every session, applies all the time.
- Skills: invoked on demand, apply only when you type
/skill-name.
A good rule: if a workflow runs 80% of the time, put it in CLAUDE.md. If it runs 20% of the time or less, make it a skill. Something like "always use pnpm" is a CLAUDE.md rule. Something like "open a PR with our team template" is a skill.
Skills vs MCP tools
Skills are prompt templates (text). MCP tools are code that Claude can call (functions). A skill shapes what Claude says to itself; an MCP tool gives Claude a new capability. They combine well: a skill might instruct Claude to use a specific MCP tool with specific arguments.
Five example skills
Here are five skills you can copy into .claude/skills/ today.
1. /commit
---
name: commit
description: Write a conventional commit for staged changes
---
Run `git diff --cached` to see what is staged.
Write a conventional commit message following this format:
`<type>(<scope>): <subject>`
Where type is one of: feat, fix, chore, docs, test, refactor, perf, style, ci, build.
Rules:
- Subject under 70 chars, imperative mood, no period.
- Body wraps at 72 chars, explains why not what.
- Footer has `BREAKING CHANGE:` if any breaking changes.
Output only `git commit -m "..."` with the message. Do not commit automatically; I will review first.
2. /pr
---
name: pr
description: Create a PR description from the current branch
---
Run `git log main..HEAD --oneline` and `git diff main...HEAD --stat` to summarize the branch.
Produce a PR description in this template:
## Summary
<two sentence overview>
## Changes
<bulleted list of logical chunks>
## How to test
<steps a reviewer can run locally>
## Screenshots
<paste if UI changes, otherwise write "N/A">
Output only the description, no commit commands.
3. /tdd
---
name: tdd
description: Write a failing test, then implement
arguments: [feature_description]
---
Implement "$@" using test-driven development.
Steps:
1. Write a test in the relevant `*.test.ts` file that captures the intent.
2. Run `pnpm test` and confirm the new test fails.
3. Implement the minimum code to make the test pass.
4. Run `pnpm test` again and confirm all tests pass.
5. Refactor if obvious duplication exists.
Do not skip steps. Pause after step 2 and show me the failing test output.
4. /review
---
name: review
description: Structured code review of staged changes
---
Review staged changes with this checklist:
1. **Correctness**: does the code do what the commit message claims?
2. **Edge cases**: null/undefined, empty arrays, negative numbers, timezone boundaries.
3. **Tests**: every new branch covered by a test.
4. **Naming**: functions and variables describe intent.
5. **Duplication**: is any existing helper available?
6. **Performance**: obvious N+1 queries or unbounded loops?
7. **Security**: untrusted input reaching shell, SQL, or DOM?
Output findings grouped by severity: blocking, suggested, optional. Do not suggest style changes; those are handled by the formatter.
5. /debug
---
name: debug
description: Structured debugging checklist for a failing test or bug
arguments: [symptom]
---
I need help debugging: $@
Work through this checklist:
1. Reproduce the issue locally. Note the exact command and output.
2. Form a hypothesis. What is the smallest change that would cause the observed behavior?
3. Add a log line or breakpoint that would prove or disprove the hypothesis.
4. Run the test again and check the log.
5. If the hypothesis was wrong, revise and repeat step 2.
6. Once the cause is known, fix it with the minimum diff.
7. Write a regression test that would have caught the bug.
Show me step 1 output before moving on.
Building a skill from a repeated workflow
The fastest path to a useful skill: notice a prompt you retype. The third time you write "look at the last 5 commits and summarize them," save it as /recap.md and parameterize the commit count with $1.
Steps to abstract:
- Copy the prompt into a new file under
.claude/skills/. - Replace any specific values (file names, counts, branch names) with argument placeholders.
- Add a description in frontmatter so it shows up in
/completion. - Test the skill once on a real task to confirm it works.
- Commit it so the rest of the team gets it on their next pull.
Team skills vs personal skills
Commit team skills to .claude/skills/ in the repo. Anyone who pulls the branch gets the same commands. Review skill changes in PRs, since a skill body runs prompts against your codebase.
Keep personal skills in ~/.claude/skills/. Private preferences, experimental workflows, and anything that would confuse a teammate stay there.
Skills calling other skills
Claude Code does not natively expand a skill from inside another skill body. But you can instruct Claude to run a skill as a step:
1. Run the workflow described in the `/review` skill against this PR.
2. Then apply the `/commit` skill to save the review as a commit note.
This pattern chains behaviors without any recursion risk.
Limits
There is no hard cap on the number of skills. A practical ceiling is around 30 before the / menu gets noisy. If you have more, split into subdirectories: .claude/skills/git/commit.md becomes /git:commit. Subdirectory names become namespaces in the completion menu.
Frequently asked questions
Where are Claude Code skills stored?
Personal skills live at `~/.claude/skills/`. Team skills live at `.claude/skills/` inside the repo and are committed to source control. Project skills override personal skills when names collide.
How do I share skills with my team?
Commit the `.claude/skills/` directory to the repo. Everyone who pulls the branch picks up the same slash commands automatically. Review changes in PRs since skills inject prompts into sessions.
Can skills call other skills?
Not directly. A skill body cannot expand another skill, but you can instruct Claude to run the workflow described in another skill as a step, which produces the same result without recursion.
How do I pass arguments to a skill?
Use positional placeholders `$1`, `$2`, `$3` or named placeholders `$NAME` in the skill body. Arguments passed on the command line fill them in order, and `$@` expands to all arguments joined with spaces.
When should I use a skill versus a CLAUDE.md rule?
Put always-applies rules in CLAUDE.md and on-demand workflows in skills. A 20% rule becomes a skill; a 80% rule belongs in CLAUDE.md so every session inherits it.
How many skills can I have?
There is no hard cap, but around 30 is a practical ceiling before the completion menu gets noisy. For more, use subdirectories like `.claude/skills/git/` which creates namespaced commands such as `/git:commit`.