Custom Commands Deep Dive — Differences from Skills and Best Practices
Mastering custom commands lets you execute repetitive workflows (blog post creation, PR reviews, i18n sync, etc.) with a single slash. This page systematically covers the structure of command files, design rules, and the steps for actually creating them.
The Difference Between Commands and Skills
Commands and Skills are easy to confuse, but their roles are completely different.
| Aspect | Commands (/command) | Skills (SKILL.md) |
|---|---|---|
| Trigger | The user types /command | Claude automatically judges based on the situation |
| Invocation | Explicit and intentional | Implicit and automatic |
| Purpose | Execute a fixed workflow | Define behavior according to context |
| File location | shared/commands/*.md | shared/skills/*/SKILL.md |
| Template variables | $ARGUMENTS is available | None |
Commands let the user decide “what to do.” Skills let Claude automatically judge “how to behave.” The division of use is: the entire workflow for writing a blog post is executed with a /blog command, while the writing style rules and quality standards within the article are defined by blog-content/SKILL.md.
The Structure of a Command File
Command files are written in Markdown format and placed in shared/commands/. .claude/commands/ is a symlink to this directory.
Basic structure:
# Command Name
A description of the command. Use `$ARGUMENTS` to receive the user's input.
## Steps
1. What to do first
2. What to do next
3. What to confirm last$ARGUMENTS expands to the argument portion when the user types /command argument. When you run /blog React's useEffect explained, the $ARGUMENTS in the command is replaced with React's useEffect explained.
A Real Example: The Structure of blog.md
The shared/commands/blog.md in this project has the following structure.
Please create or update a blog post.
## For a new post
1. Create the Japanese article in `src/content/blog/ja/` (write it first)
2. Use the frontmatter template
3. Create the corresponding English article
4. Run `node scripts/ensure-slugs.js`
5. Conduct a review and fact-check
6. Check the local preview with `npm run dev`Commands that do not use $ARGUMENTS are also valid. They are suitable for cases where an entire fixed workflow should be executed without arguments.
Best Practices
Start Command Names with a Verb
Command names should start with a verb so it is clear at a glance what they do.
| Good example | Example to avoid |
|---|---|
/blog | /article |
/sync-i18n | /i18n |
/pr | /pullrequest |
This project’s shared/commands/ has blog.md, docs.md, pr.md, sync-i18n.md, and build.md. All of them have an “action” in their name.
Use $ARGUMENTS to Accept Flexible Input
Using $ARGUMENTS lets a command receive the specific PR number, path, or topic for the current run.
# PR Summary
Please summarize the changes for the specified PR and organize the review points.
PR number or URL: $ARGUMENTS
## Steps
1. Get details with `gh pr view $ARGUMENTS --json title,body,files`
2. Check the diff of the changed files
3. Summarize and report the purpose of the changes, the scope of impact, and points to noteBe Mindful of Idempotency
Design the command so that running it twice does not break the system. For commands that create files, it is a good idea to include a step that says “if a file with the same name already exists, do not overwrite it and ask for confirmation.”
## Steps
1. Check if the target file already exists
2. If it exists, ask the user for confirmation before overwriting
3. If it does not exist, create it newInclude a Confirmation Step for Operations That Require Approval
Use the build.md design pattern as a reference. For commands involving production deployment or irreversible operations, explicitly include a step that asks for user confirmation before execution.
> ⚠️ **This command will trigger a production deployment.**
> Always ask the user for approval before executing.
## Confirmation Items Before Execution
Please confirm the following with the user before proceeding.
1. Has the local preview been confirmed?
2. Has the merge to main been completed?
3. Is it in a state that can be safely published to production?Place in shared/commands/ and Share via Symlink
In this harness design, command files live in shared/commands/ instead of being managed directly in .claude/commands/. By setting .claude/commands/ as a symlink to shared/commands/, team members can use the same command definitions.
# Check the symlink
ls -la .claude/commands
# → .claude/commands -> ../shared/commandsHands-on Exercise
Step 1: Check the Structure of an Existing Command
cat shared/commands/blog.md✅ Verify: If the file contents are displayed and include step numbers,
npm runcommands, and fact-check instructions, the read was successful.
Step 2: Actually Use the /blog Command
Launch Claude Code and run the command.
> /blog Introduction to Claude Code HarnessClaude starts creating an article following the steps in shared/commands/blog.md.
✅ Verify: If Claude starts responding with content such as “I will create a Japanese article in
src/content/blog/ja/”, the command has been loaded correctly.
Step 3: Create a New Command summarize-pr.md
Create a new file shared/commands/summarize-pr.md.
# PR Summary
Please summarize the changes for the specified PR number and organize the review points.
PR number or URL: $ARGUMENTS
## Steps
1. Get PR details with `gh pr view $ARGUMENTS --json title,body,files`
2. Check the diff of the changed files
3. Organize and report the purpose of the changes, the scope of impact, and points to watch out for in the review✅ Verify: Run
ls shared/commands/and confirm thatsummarize-pr.mdis displayed.
Step 4: Confirm the Command Works
Run the new command in Claude Code.
> /summarize-pr 123Claude fetches the content of PR #123 and starts summarizing.
✅ Verify: If Claude is seen trying to run
gh pr view 123 --json ..., the$ARGUMENTSexpansion is working correctly.
Summary
- Commands are definitions of workflows that the user explicitly invokes. Skills are definitions of behavior that Claude loads automatically
- Command files are placed in
shared/commands/in Markdown format, and.claude/commands/is a symlink - Using
$ARGUMENTSallows additional user input to be expanded within the command - Idempotency and approval flow design are the keys to commands that can be used safely in a team
Next Steps
- Skills Design Patterns — Learn how to write Skills, which are counterparts to Commands and define Claude’s automatic behavior
- Agents Spec Design — Move on to designing complex workflows using sub-agents
Frequently Asked Questions
Q: Should command files be written in .claude/commands/ or shared/commands/?
A: Write them in shared/commands/. .claude/commands/ is a symlink to shared/commands/. By writing the actual content rather than the symlink destination, Git management, team sharing, and validation by harness:check work correctly.
Q: Is there any value in a command that does not use $ARGUMENTS?
A: Yes. Commands without arguments are convenient when “executing a specific procedure the same way every time.” They are suitable for fixed routine tasks that don’t need arguments, like /sync-i18n.
Q: How do I check if a command is not being recognized?
A: First, run ls -la .claude/commands to confirm the symlink is correctly pointing to ../shared/commands. Then confirm the file exists in shared/commands/. If it still isn’t recognized, restart Claude Code.
Q: Can Commands and Skills be mixed in the same file?
A: Technically possible, but not recommended. Separating the responsibilities of Commands as “the flow the user executes” and Skills as “the definition of Claude’s behavior” improves maintainability and readability.
See the references for the external specifications and background sources used on this page.[1][2]
References
- Anthropic, Claude Code documentation
- Anthropic, Claude API documentation
For the latest releases and updates, check the official website and official documentation.