Build Your First Command — Then Grow It Into a Skill
In the previous post I argued that commands, skills, and plugins are three rungs of one ladder, and that you should start as low as you can. This is the hands-on version: we’ll build one real thing — a “review my changes before I commit” helper for Claude Code — as a command first, then feel exactly where it runs out of road and promote it to a skill.
You’ll need Claude Code installed and a project you can poke at. Everything here is copy-pasteable.
Rung 1: the command (about two minutes)
A command is just a text file whose name becomes a /shortcut. Create one
in your project:
mkdir -p .claude/commands
Then save this as .claude/commands/review-changes.md:
Review my uncommitted changes. Summarize what changed in a few bullet
points, then flag anything risky — missing error handling, hardcoded
secrets, leftover debug code, or tests that need updating. Be concise.
That’s the whole thing. Start Claude Code, type /review-changes, and it
runs that prompt. You’ve just turned a paragraph you’d otherwise retype
into a one-word trigger.
Two things worth knowing:
- Put the file in
.claude/commands/and it lives with the project (and can be committed for teammates). Put it in~/.claude/commands/instead and it follows you across every project. - You can make it take input. Drop a placeholder in and
$ARGUMENTS
A placeholder in your command file that gets replaced with whatever you type after the command name. Write/fix-issue 123and the text123lands wherever$ARGUMENTSappears in the file — so one command template works for any input./review-changes only the auth modulewill pass “only the auth module” straight into the prompt.
Where the command hits its ceiling
Use it a few times and two limitations show up:
- You have to remember to run it. It never fires on its own. When you
finish a change and don’t think to type
/review-changes, it does nothing. - It’s only a prompt. Whether it actually sees your real diff depends on Claude going and fetching it each time. There’s no guarantee the review is grounded in your actual current changes rather than a guess from whatever files happen to be open.
Neither is fixable at the command rung. That’s your signal to climb.
Rung 2: promote it to a skill
A skill is the same idea in a folder, with two upgrades that fix exactly those two problems. Move the file:
mkdir -p .claude/skills/review-changes
Save this as .claude/skills/review-changes/SKILL.md:
---
description: Review the user's uncommitted changes and flag anything risky.
Use when the user asks to review their changes, check their diff, or
whether their work is ready to commit.
allowed-tools: Bash(git diff *) Bash(git status *)
---
## The current changes
!`git diff HEAD`
## Your task
Summarize the changes above in a few bullet points, then flag anything
risky — missing error handling, hardcoded secrets, leftover debug code, or
tests that need updating. If the diff is empty, say so.
Same instructions as before, but three things changed, and each one earns its keep:
The description makes it automatic. This line is what Claude reads to
decide when the skill is relevant. Now you can just ask “can you check my
changes before I commit?” and Claude reaches for the skill on its own —
that’s model invocation
The headline difference between a command and a skill: instead of you
typing a slash command, the model reads each skill’s description and pulls
in the matching one by itself when your request fits. You can still trigger
it manually with /review-changes too.
The !`git diff HEAD` line grounds it in reality. That syntax is dynamic context injection
A line in the skill that runs a shell command and drops the output into
the prompt before the AI ever sees it. So the skill arrives with your
actual, current git diff already pasted in — not a description of it, and
not something the model has to remember to go fetch.
git diff HEAD first and pastes the real result
into the prompt. The review is now always about your actual current
changes, automatically. No more hoping it went and looked.
The allowed-tools line removes the friction. It pre-approves those
specific git commands so the skill runs without stopping to ask permission
each time.
Restart Claude Code (a brand-new skills folder needs one restart; edits
after that are picked up live), make an edit to any file, and try it both
ways — type /review-changes, or just ask “is my work ready to commit?”
Either way you get a review grounded in your real diff.
Know when to stop climbing
You’ve now got something genuinely useful, and for most people this is the right place to stop. You’d only go further if you needed to:
- Bundle more than a prompt — say, a checklist file the skill reads
only when needed, or a script it runs to do real work. That’s still a
skill; just add files to the folder and point to them from
SKILL.md. - Hand it to your whole team as a package with versioned updates. That is the jump to a plugin — and not before someone actually wants it.
The mistake, as always, is climbing higher than the problem requires. You didn’t build and publish anything to get here — you wrote one file, then grew it into a folder the moment a real limitation pushed you to.
The takeaway
Start at the bottom rung on purpose. A command took two minutes and solved the “stop retyping this” problem. When it hit its ceiling — no automatic triggering, no guarantee it saw your real changes — promoting it to a skill was a five-minute edit that fixed both. Let the limitations you actually hit pull you up the ladder, one rung at a time.
Companion piece: Commands, Skills, and Plugins: Which One Do You Actually Need? — the map for the ladder you just climbed.