Bible Network Crypto DeFi Onchain RWA AI Agent Stablecoin Chain SAFU CryptoTax DeFAI AGI Claude Me Claude Skill Claude Design Claude Cowork
Independent Media
Not affiliated with any project
Learn Claude Skills. Do Everything Better.
claudeskill-me.com
LATEST
Why a Single "hi" Can Burn 20,000+ Tokens in Claude Code: Breaking Down the Fixed Startup Overhead  ·  How to Write Your First Custom Slash Command in Claude Code: A Working Example From Scratch  ·  Claude Code Merged Custom Commands Into Skills — Most "Commands vs Skills" Guides Are Already Outdated  ·  Why Your Claude Code Skill Silently Stops Triggering: The 15,000-Character Description Budget No One Warns You About  ·  Effort vs. Temperature in Claude: What's the Difference, and Why One of Them No Longer Works on Newer Models  ·  anthropics/skills Review: The Official GitHub Repo Has 168k Stars and Solid Content — The Problem Is You Might Never Find It
prompt-examples

How to Write Your First Custom Slash Command in Claude Code: A Working Example From Scratch

30-Second Version · For the impatient
If a tutorial's example command still shows a /project: prefix, that tutorial has already fallen behind the current official syntax.

Full Explanation +
01 · Why did this happen?

How should I choose between the $ARGUMENTS variable and named arguments (like $issue, $branch)?

The deciding factor is whether the command needs multiple, distinctly purposed inputs. If a command only needs a whole chunk of text passed through as-is (say, "which environment to deploy to"), $ARGUMENTS drops everything typed after the command name straight in, unchanged — the simplest approach.

If a command needs several distinctly purposed pieces of input at once (say, "migrate a given component from one language to another," needing the component name, source language, and target language all together), named arguments are clearer — list argument names in the frontmatter's arguments field, then reference each individually as $name in the content. For example, arguments: [component, from, to] paired with $component, $from, and $to in the body: running /migrate SearchBar JavaScript TypeScript maps the three names to the three inputs in order — far more reliable than stuffing everything into a single $ARGUMENTS and asking Claude to parse it apart itself.

02 · What is the mechanism?

If my command needs multiple lines of shell commands, not just one, how should I write that?

Single-line dynamic context injection uses the !command syntax at the start of a line (note the backtick position, and ! must appear at the start of the line or immediately after whitespace, or it gets treated as plain text and the command never runs). If you need to run several lines of commands at once, use the fenced-Block syntax instead, opened with three backticks and an exclamation mark:

## Environment

<a href="https://crypto-bible.com/en/glossary/blockchain-fundamentals/node/" target="_blank" rel="noopener">Node</a> --version
git status --short
```</code></pre><p>This block form injects the output of multiple lines of commands all at once, suited to situations needing several pieces of environment information queried together, without having to split every line into a separate <code>!` `</code> statement.
03 · How does it affect me?

I wrote and tested the command successfully, but later edited the Skill.md content — does Claude Code need a restart to pick that up?

No, if you're editing existing command content under .claude/skills/ at the personal or project level, Claude Code detects the change live within the current session and applies it, no restart needed. This live detection covers adding, modifying, and removing content inside a command's directory.

There's one exception: if you create a brand-new top-level skills directory that didn't previously exist, after the session has already started (say, your project didn't have a .claude/skills/ folder at all, and you manually created it mid-session), Claude Code needs a restart before it starts watching that newly-appeared directory — because the live-detection mechanism itself watches directories that already existed at session startup.

04 · What should I do?

Others on my team also want to use this command I wrote — how do I share it with them?

It depends on the scope you want to share at. If you want every collaborator on the same project to have access, the most direct approach is committing the .claude/skills/summarize-changes/ folder into version control (adding it to the Git repo, for instance) — anyone who clones the project then gets the command working automatically, no extra install step needed. This is also one of the officially recommended ways to share this kind of command at the project level.

For broader sharing — say, making the same set of commands available not just to one project but to an entire team or organization — consider packaging it as a Plugin, or deploying it uniformly through organization-level managed settings. Committing to version control is entirely sufficient for sharing a single command; only once the number of commands grows and needs reuse across multiple projects is it worth the extra effort of a more formal distribution format.

Full Content +

Search "how to write a custom slash command in Claude Code" and you'll find plenty of tutorials — but some of them show the /project:command_name style with a namespace prefix, which is no longer the recommended approach in current official documentation. This piece walks through the complete process using today's official standard: creating the directory, writing the file, and actually testing it, flagging the common trip points along the way.

Setup: a concrete use case

Rather than an abstract "Hello World" example, this uses something genuinely useful: a command that summarizes uncommitted changes in the current Git project and flags anything risky. This scenario is deliberately a step more complex than a plain-text instruction, so you can also see how the more advanced technique of injecting live data dynamically actually works.

Step one: create the directory

The current official approach is writing a command as a Skill directory rather than a single .claude/commands/ file (the latter still works, but isn't the currently recommended way to write something new). If you want this command available only in the current project, create a project-level directory:

mkdir -p .claude/skills/summarize-changes

If you want it available across all your projects, put it at the personal level instead:

mkdir -p ~/.claude/skills/summarize-changes

Step two: write SKILL.md

The directory name itself becomes the command name you type later, so a folder named summarize-changes means typing /summarize-changes to trigger it. Create a SKILL.md file inside that directory, split into two parts: YAML Frontmatter wrapped in --- at the top telling Claude when to use this command, and the actual instructions below it.

---
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 missing error handling, hardcoded values, or tests that need updating. If the diff is empty, say there are no uncommitted changes.

The line worth explaining specifically is !git diff HEAD — this is dynamic context injection syntax. Claude Code runs this command in the background first, replacing this line with the actual output, so what Claude reads is a complete prompt that already includes the real, current diff content — not an empty instruction it would have to figure out how to look up itself. This is also the key difference between a custom command and a plain-text prompt: a command can look up live data for you first, then hand that data to Claude alongside the task.

Step three: test it

In a Git project, make a small edit to any file, start Claude Code, and test in either of two ways: type something matching the situation described in description, like "what did I change?", and let Claude judge automatically whether to load this command, or trigger it directly:

/summarize-changes

Either way should get Claude to respond with a short change summary plus a few risk callouts.

A common outdated syntax trap: stop writing the /project: prefix

If you're referencing an older tutorial article, you'll likely see examples written as /project:command_name or /user:command_name — namespace-prefixed triggering syntax. This is the older system's style; current official documentation's examples have consistently moved to plain /command-name, with no extra prefix needed. If you copied an old tutorial's prefixed command and it didn't respond, this is usually why. One simple way to gauge whether a tutorial is current: check whether its example triggering syntax still includes that prefix.

One step further: locking a dangerous action to manual-only

If the next command you want to write involves an action with real consequences (deployment, sending a message), adding disable-model-invocation: true to its frontmatter ensures it only runs when you type it yourself — Claude won't trigger it just because it judges "the timing looks right":

---
name: deploy
description: Deploy the application to production
disable-model-invocation: true

Deploy $ARGUMENTS to production:

  1. Run the test suite
  2. Build the application
  3. Push to the deployment target
  4. Verify the deployment succeeded

Here, $ARGUMENTS gets replaced with whatever you type alongside the command — running /deploy staging, for instance, means Claude receives "Deploy staging to production."

What this means for how you write commands going forward

Once your first command is done, the next time you catch yourself thinking "I've pasted this exact prompt three times already," that's the signal to write it as a command. Before starting, ask yourself two questions: does this workflow need live data injected dynamically (deciding whether you need the ! syntax), and does this workflow have real side effects (deciding whether to add disable-model-invocation: true). Working those two out first, then writing against the current official syntax, is more reliable than copying a tutorial of uncertain age.

Sources: Extend Claude with skills - Claude Code Docs, How to create your first custom slash command - SFEIR Institute
Ask a Question
Please enter at least 10 characters
Related Articles
How to Actually Use XML Tags in Prompts: 3 Before/After Examples vs. Plain Text
prompt-examples · Aug 31
Claude Code Merged Custom Commands Into Skills — Most "Commands vs Skills" Guides Are Already Outdated
skill-library · Sep 05
Why Your Claude Code Skill Silently Stops Triggering: The 15,000-Character Description Budget No One Warns You About
practice · Sep 02
anthropics/skills Review: The Official GitHub Repo Has 168k Stars and Solid Content — The Problem Is You Might Never Find It
reviews · Sep 02
Related News
More Related Topics