Turn prompts you repeat into your own Claude Code commands
A skill is a small Markdown file that becomes a /command of your own. Write one for the checklist you keep pasting, include current data such as your git diff, and choose whether Claude may use it on its own.
Checked against the official documentation on
On this page11 sections
If you keep typing the same instructions ("summarize my changes and flag anything risky", "commit this with a proper message", "check the disk and memory"), you can turn each one into a command of your own. Type /summarize-changes and Claude gets the full instructions, with the data it needs already filled in.
In Claude Code these are called skills. This guide shows how to write one, how to pass it arguments and the output of commands, how to decide who may run it, and the safety points to check before you use skills from someone else's repository.
Skills and custom commands are the same thing now
Older guides talk about custom commands in .claude/commands/. Those have been merged into skills. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and work the same way. Your old command files keep working.
Skills add a few things on top: a folder for extra files, settings that control whether Claude may run the skill on its own, and the ability for Claude to pick a skill up automatically when it fits what you asked.
Where skills live
Each skill is a folder with a SKILL.md file inside. Where you put the folder decides where the skill works:
~/.claude/skills/<name>/SKILL.md: a personal skill, in every project on your machine..claude/skills/<name>/SKILL.mdin a project: in that project only. Commit it and everyone working on the project gets it.
The folder name becomes the command. .claude/skills/summarize-changes/SKILL.md gives you /summarize-changes. If a personal skill and a project skill have the same name, the personal one runs.
Your first skill
This skill summarizes your uncommitted changes and points out anything risky. It is adapted from the example in the official documentation.
Create the folder
Shell · your usermkdir -p .claude/skills/summarize-changesWrite SKILL.md
.claude/skills/summarize-changes/SKILL.md--- description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff. --- ## Current changes !`git diff HEAD` ## Instructions Summarize the changes above in two or three bullet points, then list any risks you notice, such as hardcoded passwords, changed limits or missing error handling. If the diff is empty, say there are no uncommitted changes.Run it
Claude Code/summarize-changes
The file has two parts:
- The frontmatter, between the
---lines. Here it holds only thedescription, which tells Claude what the skill is for and when to use it. - The body, the instructions Claude follows when the skill runs.
The line !`git diff HEAD` is not an instruction for Claude. Claude Code runs the command first and puts its output in that spot, so Claude receives your actual diff, not a request to go and get it.
In our test, a change that raised a limit from 10 to 1000 and added a password to a PHP file came back as two bullet points, followed by risks that included "Hardcoded password" and "Limit raised 100×".
Let Claude find it on its own
You don't have to type the command. Claude sees each skill's description, and when your request fits one, it loads the skill itself. In our test, the plain question below was enough: Claude called the summarize-changes skill without being told to.
What did I change?That makes the description the most important line in the file. Say what the skill does first, then the requests it should answer, in the words people actually use: "Use when the user asks what changed, wants a commit message, or asks to review their diff."
Decide who may run it
Some skills should never run unless you ask. You don't want Claude deciding on its own that now is a good time to deploy. Two frontmatter settings control this:
disable-model-invocation: true: only you can run it, by typing the command. Claude does not even see it in its list. Use it for anything with side effects: commits, deploys, sending messages.user-invocable: false: only Claude can use it. It disappears from the/menu. Use it for background knowledge, such as how an old system works, which is not a command anyone would type.
We tested the first one with a manual-only server report. Asked in plain words for "a short health report for this server using the server-report skill", Claude did not use the skill and ran its own commands instead. Typing /server-report ran the skill.
Pass arguments
Whatever you type after the command reaches the skill as $ARGUMENTS. This /commit skill uses it for the commit message:
---
description: Stage all changes and commit them with the given message
disable-model-invocation: true
argument-hint: [commit message]
allowed-tools: Bash(git add *) Bash(git commit *) Bash(git status *)
---
Stage all changes with `git add -A` and commit them with this message: $ARGUMENTS
If no message was given, write a one-line message from the diff. Then show the result of `git status --short`./commit Raise limit to 1000argument-hintis the hint shown while you type the command.- To take arguments one by one, use
$0,$1and so on:/deploy staging v2makes$0equalstagingand$1equalv2. Wrap a value in quotes to keep several words together. allowed-toolslets the skill run those commands without asking you. Our test commit went through with no permission prompt. The approval lasts only for that turn: it ends when you send your next message.
Claude still uses its judgment inside a skill. On our first try, the change included a password written into the code, and instead of committing, Claude stopped and asked whether to remove it first.
Feed a skill the output of commands
The !`command` lines are what make skills useful for server work. This one collects the numbers for a quick health report:
---
description: Short health report for this server (disk, memory, load)
disable-model-invocation: true
allowed-tools: Bash(systemctl --failed *)
---
## Disk
!`df -h /`
## Memory
!`free -h`
## Load
!`uptime`
## Failed services
!`systemctl --failed --no-legend`
## Instructions
Write a five-line health report from the numbers above. Say plainly if disk use is over 80 percent or if memory is nearly full.These commands never stop to ask for permission. Claude Code checks each one against your permission rules first:
- Read-only commands that Claude Code recognizes run as they are. In our test,
df,freeanduptimeneeded nothing. - Any other command that your rules don't allow stops the whole skill before it reaches Claude.
Without the allowed-tools line, systemctl --failed stopped the skill with:
Output
Shell command permission check failed for pattern "!`systemctl --failed --no-legend`": This command requires approvalThe allowed-tools line in the file above fixes it, by approving systemctl --failed commands for this skill only.
Warning
In a claude -p run, that failure is easy to miss: the run ended with no output and exit status 0, and the error only showed up in the detailed JSON output. If a skill in a script returns nothing, check its !`command` lines first.
A command that exits with an error also stops the skill. If a command is expected to exit with a non-zero code, for example a check script that reports problems that way, end the line with || true.
Skills from someone else's repository
Three points from the documentation are worth knowing before you work in a repository you did not write:
- A project skill's
allowed-toolsapplies even if you never trusted the folder, including inclaude -pruns. That is different from allow rules in.claude/settings.json, which wait for the trust dialog. We saw it in our test: the folder had never been trusted, and/commitstill rangit addandgit commitwithout a prompt. A skill can approve broad access for itself. Read theallowed-toolslines in the repository's.claude/skills/before you run Claude Code there. - The
!`command`lines run on your machine when the skill runs. They still pass the permission check, butallowed-toolscan approve them. - You can switch off those command lines entirely with
"disableSkillShellExecution": truein your settings. Each command is then replaced with a note instead of being run.
Keep skills short
- A skill's full text loads only when it runs. Until then, only its description takes up space, so a long skill costs almost nothing while it sits unused.
- Once it runs, its text stays in the conversation. Every line costs tokens on every later turn, so write what to do, not why.
- The documentation suggests keeping
SKILL.mdunder 500 lines. Put long reference material in other files in the same folder, and say inSKILL.mdwhich file holds what, so Claude reads them only when needed.
When a skill does not show up
- Check the path. It must be
.claude/skills/<name>/SKILL.md, withSKILL.mdin capitals. - Check the first line. The frontmatter is read only if the opening
---is the very first line of the file. - Check the field names. They must match exactly, hyphens included. Claude Code ignores a field it does not recognize without any error.
- If Claude never picks it up on its own, rewrite the description with the words you actually use when you ask, or just type the command.
- If it runs too often, make the description narrower, or add
disable-model-invocation: true.
Sources
- Extend Claude with skills, Claude Code documentation
- Configure permissions, Claude Code documentation
- Agent Skills, the open standard Claude Code skills follow
Checked on
Claude Code 2.1.280 on AlmaLinux 9.8. All three skills were tested in a throwaway git project with claude -p: direct invocation, automatic invocation from a plain question, the manual-only setting, arguments, allowed-tools, the permission check on !`command` lines, and allowed-tools in a folder that had never been trusted. The messages above were copied from those runs.