はじめに / 対象と前提
「PR 前のセルフレビューして」「この Issue 直して」— 毎回ほぼ同じプロンプトを Claude Code に打っているなら、カスタムスラッシュコマンドにしておくと楽になる。Markdown を 1 枚置くだけで /review のように呼べる。
ただ、実際に作ると ! で書いたシェルコマンドが展開されない、引数の受け取り方が思っていたのと違う、サブディレクトリに分けたら名前がぶつかる、の 3 つで地味に詰まった。この記事はその手順と回避策をまとめる。
- 想定読者:Claude Code を日常的に使っていて、定型プロンプトを使い回したい人
- 動作確認環境:Claude Code 2.x 系(2026 年 10 月時点)/ macOS / zsh / git 2.4x
- 前提:
.claude/ディレクトリとsettings.jsonの位置が分かること
最近の Claude Code ではスラッシュコマンドと Agent Skills の仕組みが統合されつつあるが、
.claude/commands/*.mdは引き続きそのまま動く。同名の Skill があるとそちらが優先されるので、移行中の人は名前の重複に注意。
TL;DR
-
.claude/commands/<名前>.mdを置けば/<名前>で呼べる(ユーザー共通なら~/.claude/commands/) - 本文中の
!+ バッククォートのシェル実行は、frontmatter のallowed-toolsに該当 Bash を許可しないと動かない -
$1$2は 空白区切り。自由文は$ARGUMENTSで受けて最後に置く。サブディレクトリは名前空間にならないので ファイル名をユニークに
手順 / 動かし方
1. 最小のコマンドを作る
mkdir -p .claude/commands
cat > .claude/commands/explain.md <<'EOF'
次のコードを、5 年目の Web エンジニア向けに 3 行で説明して。
専門用語には一言で補足をつけること。
対象: $ARGUMENTS
EOF
Claude Code を開いて / を打つと、候補に /explain が (project) 付きで出る。
> /explain @src/lib/retry.ts
@パス を書くとファイル内容がコンテキストに入るので、$ARGUMENTS 経由で渡せばそのまま説明させられる。
2. frontmatter で説明・引数ヒント・許可ツールを付ける
実用的なのは「git の差分を事前に取り込んでレビューさせる」パターン。
---
description: ステージ済みの差分をセルフレビューする
argument-hint: [重点的に見たい観点(任意)]
allowed-tools: Bash(git diff:*), Bash(git status:*), Bash(git log:*)
---
## 現在の状態
- ブランチと状態: !`git status --short --branch`
- 直近のコミット: !`git log --oneline -5`
- ステージ済み差分: !`git diff --cached`
## 依頼
上の差分を PR 前のセルフレビューとして確認して。
- バグ・境界条件の漏れ・エラー処理の欠落を優先
- スタイル指摘は最後にまとめて 3 件まで
- 追加の観点: $ARGUMENTS
.claude/commands/review.md として保存し、/review 認可まわり のように呼ぶ。! の行はプロンプトが Claude に渡る 前に 実行され、その出力が埋め込まれる。Claude が自分で git diff を叩くより往復が 1 回減り、毎回同じ前提で見てくれるのが利点。
3. 位置引数を使う
---
description: Issue 番号と優先度を指定して修正方針を立てる
argument-hint: <issue番号> <優先度> [補足]
---
Issue #$1 を優先度 $2 で対応する。
まず原因の仮説を 3 つ挙げ、確認手順を示してから修正に入ること。
> /fix-issue 482 high
$1 に 482、$2 に high が入る。
動作確認
/review 実行後、Claude の最初の応答に差分のファイル名が具体的に出てくれば ! が展開されている。出てこず「差分を確認します」と自分で git を叩きに行く場合は、次のハマりどころ 1 を疑う。
ハマりどころ
1. ! のシェル実行が展開されない
症状:! の行が実行されず、権限エラーになる、または Claude が改めて Bash を使おうとして許可待ちで止まる。
原因:! による事前実行も Bash ツールの権限チェックを通る。frontmatter の allowed-tools に該当コマンドが無く、settings.json 側でも許可されていないと実行されない。
回避策:使うコマンドを allowed-tools に プレフィックス単位で 列挙する。
allowed-tools: Bash(git diff:*), Bash(git status:*), Bash(git log:*)
Bash(git:*) のように広く取ると楽だが、git push まで通るので避けた。読み取り系だけ許すのが無難。もう一点、! とバッククォートの間に空白を入れると単なる文字列として扱われるので、!`git diff` と詰めて書く。
2. $1 と $ARGUMENTS の分割が直感と違う
症状:/fix-issue 482 ログイン後に 500 が出る と打つと、$2 に「ログイン後に」しか入らない。
原因:位置引数は 空白で単純に分割 される。日本語の文でも空白があればそこで切れる。
回避策:
- 位置引数は「ID・フラグ・優先度」など 空白を含まない値 に限定する
- 自由文は
$ARGUMENTSで受ける。ただし$ARGUMENTSは 全引数の文字列 なので、$1と併用すると先頭の値が二重に入る - 引数なしで呼ばれた場合に備えて、本文に「空なら〇〇として扱う」と一文書いておく(空文字のまま渡るため)
Issue #$1 を対応する。
補足情報(全引数): $ARGUMENTS
※ 補足が Issue 番号だけの場合は、Issue 本文を読んで判断すること。
3. サブディレクトリに分けたら名前が衝突した
症状:.claude/commands/frontend/test.md と .claude/commands/backend/test.md を作ったら、/test が片方しか期待どおりに動かない。
原因:サブディレクトリは 一覧の説明欄に (project:frontend) と表示されるだけ で、コマンド名には含まれない。どちらも /test になる。プロジェクトとユーザー(~/.claude/commands/)に同名ファイルがある場合も同様に衝突する。
回避策:ファイル名自体に接頭辞を付ける。
.claude/commands/
├── fe-test.md # /fe-test
├── be-test.md # /be-test
└── review.md # /review
ディレクトリ分けは整理用と割り切り、名前の一意性はファイル名で担保する。
背景・補足
-
descriptionは一覧表示だけでなく、Claude 自身がコマンドを呼び出してよいか判断する材料にもなる。勝手に呼ばれたくないコマンド(デプロイ系など)は frontmatter にdisable-model-invocation: trueを付けておく -
modelを frontmatter で指定すると、そのコマンドだけ軽いモデルで回せる。要約・説明系は軽いモデルで十分だった -
.claude/commands/をリポジトリにコミットすれば、チーム全員が同じコマンドを使える。個人の癖が強いものは~/.claude/commands/側に置く
まとめ
- カスタムスラッシュコマンドは Markdown 1 枚で作れて、定型プロンプトの打ち直しが無くなる
-
!の事前実行はallowed-toolsに読み取り系 Bash をプレフィックスで許可しないと動かない - 位置引数は空白区切り。自由文は
$ARGUMENTS、空のときの扱いも本文に書く - サブディレクトリは名前空間にならない。ファイル名に接頭辞を付けて衝突を避ける