Tutorial

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
    $ARGUMENTS A placeholder in your command file that gets replaced with whatever you type after the command name. Write /fix-issue 123 and the text 123 lands wherever $ARGUMENTS appears in the file — so one command template works for any input.
    placeholder in and /review-changes only the auth module will 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:

  1. 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.
  2. 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.
. Word this line carefully: too vague and it never triggers, too broad and it fires when you didn’t want it.

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.
: Claude Code runs 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.