Claude Code Skills Primer — Build Your Own Commands with SKILL.md
An overview of Claude Code "skills." A skill is a folder with instructions in a SKILL.md, and it becomes a homemade command callable as /skill-name. The older "custom slash commands" (.claude/commands/*.md) were merged into skills (the old format still works).
What is a skill?
- Write instructions in a
SKILL.mdand it can be invoked by you as/nameor loaded automatically by Claude when a related task comes up - The difference from CLAUDE.md is load timing. CLAUDE.md enters the context in full every session, while a skill keeps only its description resident and loads its body on use. Long procedures are cheaper as skills
- Rule of thumb: "facts and conventions" go in CLAUDE.md, "procedures and checklists" go in skills. Pasting the same instructions into chat twice is the signal to make a skill
Where skills live
| Scope | Path | Applies to |
|---|---|---|
| Personal | ~/.claude/skills/NAME/SKILL.md |
All of your projects |
| Project | .claude/skills/NAME/SKILL.md |
That repository only (commit it to share) |
| Plugin | PLUGIN/skills/NAME/SKILL.md |
Wherever the plugin is enabled |
- On name collisions, personal beats project. Bundled skills (
/code-reviewetc.) can also be overridden by a same-named skill of yours - In a monorepo, subdirectory
.claude/skills/folders are auto-discovered too (they get directory-qualified names likeapps/web:deploy) - Adding or editing files takes effect immediately, no session restart
Writing SKILL.md
---
name: deploy
description: Deploy the app to production. Use when asked to deploy or release
disable-model-invocation: true
---
Deployment steps:
1. Run the tests
2. Build
3. Push to the deployment targetAll frontmatter is optional (though you should write description — Claude uses it to decide on automatic invocation). The main fields:
| Field | Role |
|---|---|
description |
What the skill does + when to use it. Input for auto-invocation decisions |
disable-model-invocation: true |
Forbids automatic invocation by Claude. Only you can call it (essential for side-effecting things like deploy/commit) |
user-invocable: false |
Hidden from the / menu. Background knowledge only Claude uses |
argument-hint |
Argument hint shown during completion (e.g. [PR number]) |
allowed-tools |
Tools that run without approval while this skill executes (e.g. Bash(git add *)) |
context: fork |
Run as a subagent in a separate context |
model / effort |
Override the model / thinking depth only while this skill runs |
paths |
Auto-invoke only when files matching the glob are touched |
Who can invoke what
| Setting | You | Claude | Use case |
|---|---|---|---|
| Default | ○ | ○ | General procedures and knowledge |
disable-model-invocation: true |
○ | × | Side-effecting operations like /commit /deploy |
user-invocable: false |
× | ○ | Background knowledge, e.g. legacy-spec notes |
Arguments and dynamic context
$ARGUMENTS= all invocation arguments.$0$1reference them individually; witharguments: [issue, branch]in frontmatter you get named ones like$issue- Writing
!`command`in the body means the command runs before Claude reads the skill and its output replaces the placeholder — dynamic context injection- Example: embed
!`git diff HEAD`and the skill always starts with the latest diff already in its body
- Example: embed
${CLAUDE_SKILL_DIR}references the skill's own directory,${CLAUDE_PROJECT_DIR}the project root
Companion files
A skill is a folder, so files other than SKILL.md can live there too.
my-skill/
├── SKILL.md ← the core (required; keep under ~500 lines)
├── reference.md ← detailed material (read only when needed)
└── scripts/
└── helper.js ← a script Claude executesReference them from SKILL.md ("see reference.md for details") and Claude reads them only when necessary. The thinner the main body, the better the token efficiency.
Real examples from this repo
This monorepo keeps the following under .claude/skills/, all operated as "invoked by me" (the disable-model-invocation style):
/commit— commit message conventions (Conventional Commits + Japanese summaries) and the push procedure/blog-article— the procedure for generating app-introduction articles in 6 languages (screenshot commands included)/x-announce— demo GIF capture and post drafting for X announcements (with a character-count script bundled)
Turning "the procedure I explained every time" into a skill reduces the request to a single /blog-article. Bundling scripts is the killer feature: fixed processing like GIF encoding and character-count validation is frozen into .js files inside the skill.
Summary
- A skill = a homemade command that exists by placing a
SKILL.md. Its body loads only on use, so it is cheaper than CLAUDE.md - Side-effecting procedures get
disable-model-invocation: trueto stay you-only - The practical power moves:
!`command`dynamic injection and bundled helper scripts - Details in the official docs