これは、なにをしたくて書いたもの?
Claude Codeにはユーザーが拡張できる機能がいろいろとありますが、なんとなく雰囲気で見ている気がするのでひとつずつちゃんと
見ていこうかなと思いまして。
今回はカスタムスラッシュコマンドを見ていこうと思います。
カスタムスラッシュコマンド
スラッシュコマンドのドキュメントはこちら。
Slash commands - Claude Code Docs
スラッシュコマンドには組み込みのものと、ユーザーが定義できるカスタムスラッシュコマンドがあります。
今回はカスタムスラッシュコマンドに注目します。カスタムスラッシュコマンドはMarkdownファイルとして作成し、以下の構文で呼び出します。
/<command-name> [arguments]
<command-name>はMarkdownファイルから.mdを除いた名前、[arguments]はコマンドライン引数です。
カスタムスラッシュコマンドは、配置先によって2つのタイプがあります。
.claude/commands/(プロジェクトコマンド)- リポジトリーに保存され、チームで共有されるコマンド
/helpで見た時に(project)と表示される
$HOME/.claude/commands/(個人用コマンド)- すべてのプロジェクトで利用できるコマンド
Slash commands / Custom slash commands / Command types
2つの配置先で競合した場合は、「サポートされない」とだけ書かれていますね。
ところで、「プロジェクト」という用語がドキュメント内で明示的に述べられていない気がするのですが、Claude Codeを起動した
ディレクトリーのことをそう呼んでいる感じですね。
Open your terminal in any project directory and start Claude Code:
Quickstart / Step 3: Start your first session
機能面について。
- 引数へのアクセス
- すべての引数を指す時は
$ARGUMENTSを使用 - 個別の引数を指す時は
$1、$2のようなシェルスクリプトと同じ位置パラメーターを使用
- すべての引数を指す時は
- Bashツールを使用することでコマンド実行が可能
@prefixを使うことでファイル参照が可能
Slash commands / Custom slash commands / Features
これらの情報はFrontmatterで指定します。Frontmatterで指定できる情報は以下です。
- 利用できるツール(
allowed-tools)- 指定されていない場合は会話内から継承
- Claude Codeでデフォルトで選択できるツールはこちら
- 引数(
argument-hint) - コマンドの簡潔な説明(
description) - モデル(
model)- 指定されていない場合は会話内から継承
- SlashCommandツールからの利用可否(
disable-model-invocation)- デフォルトは利用可能
Slash commands / Custom slash commands / Frontmatter
ドキュメントを見たところで、あとは実際に使ってみましょう。
Claude Code+Claude Code Router(Gemini)で試します。
環境
今回の環境はこちら。
$ claude --version 2.0.42 (Claude Code) $ ccr version claude-code-router version: 1.0.66
Claude Code RouterはGeminiを使うように設定しています。
$HOME/.claude-code-router/config.json
{ "PORT": 3456, "Providers": [ { "name": "gemini", "api_base_url": "https://generativelanguage.googleapis.com/v1beta/models/", "api_key": "xxxxx", "models": ["gemini-2.5-flash", "gemini-2.5-flash-lite", "gemini-2.5-pro"], "transformer": { "use": ["gemini"] } } ], "Router": { "default": "gemini,gemini-2.5-flash", "think": "gemini,gemini-2.5-flash", "webSearch": "gemini,gemini-2.5-flash" } }
起動はこちらで。
$ ccr code
カスタムスラッシュコマンドを作ってみる
ひとまず、カスタムスラッシュコマンドを作ってみましょう。
以下のようなファイルを作成。
.claude/commands/greeting.md
--- description: 挨拶 --- 日本語で挨拶してください。
Claude Codeで使おうとすると、このように表示されます。
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── > /gre ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── /greeting 挨拶 (project)
使ってみましょう。
> /greeting is running… ● こんにちは!何かお手伝いできることはありますか?
動きましたね。これで初めてのカスタムスラッシュコマンドが動かせました。
カスタムスラッシュコマンドは、Claude Codeの起動時に読み込まれるようです。追加したり定義を変更したりした場合は、Claude Codeを
起動し直す必要がありそうです。
引数を取るカスタムタムスラッシュコマンドを作成してみる
次は引数を取るカスタムスラッシュコマンドを作成してみましょう。
.claude/commands/greeting-args.md
--- argument-hint: [name] description: 引数付き挨拶 --- $1 にはあなたの名前が指定されます。指定された名前からキャラクターを連想し、簡単な自己紹介を返してください。
呼び出そうとすると、こんな感じでヒントとして引数の情報が現れます。
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── > /greeting-args [name] ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
実行。
> /greeting-args is running… 桃太郎 ● 桃から生まれた桃太郎です!鬼ヶ島への冒険、ご一緒しませんか?
OKですね。
$ARGUMENTSを使ってみましょう。
.claude/commands/choise-number.md
--- argument-hint: [one] [two] [three] description: 数字を選択 --- $ARGUMENTSの中に数字があれば、それを教えてください。
ヒント表示。
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── > /choise-number [one] [two] [three] ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
呼び出し。
> /choise-number is running… foo 10 bar ● "foo 10 bar" の中に見つかった数字は 10 です。
よさそうです。
ところで、ドキュメントのargument-hintにはこんな例が書かれています。これはなんでしょう?
argument-hint: add [tagId] | remove [tagId] | list
これはサブコマンドの例のようです。addやremove、listは固定の引数ということですね。
こんなサンプルを作成。
.claude/commands/calc.md
--- argument-hint: plus [a1] [a2] | minus [b1] [b2] | help description: 引数付き挨拶 --- 回答は日本語で行ってください。 $1にplusが指定された場合、$2 と $3 を加算して結果を教えてください。 $2にminusが指定された場合、$2 から $3 を減算して結果を教えてください。 $3にhelpが指定された場合、plusとminusの使い方を教えてください。
使おうとすると、このようにヒントが表示されます。
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── > /calc plus [a1] [a2] | minus [b1] [b2] | help ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
実行。
> /calc is running… plus 3 5 ● 3と5を足すと8になります。 > calc minus 10 3 ● 10から3を引くと7になります。 > calc help ● plus [a1] [a2]:[a1] と [a2] を加算します。 minus [b1] [b2]:[b1] から [b2] を減算します。
よさそうです。
まったく関係ない引数を指定すると、こうなりました。
> /calc is running… unknown
● 申し訳ありませんが、無効な引数です。plusまたはminusの後に2つの数値を指定するか、helpを指定してください。
ファイル作成とコマンド実行
最後に、ファイル作成とコマンド実行をさせてみます。ここではツールの指定も合わせてみていこうと思います。
まずはこんなカスタムスラッシュコマンドを作成。ツールは指定しません。
.claude/commands/java-hello-world.md
--- argument-hint: [class-name] description: Hello Worldを出力するJavaプログラムを作成して実行します --- `$1.java`というファイルに、「Hello World」を出力するJavaプログラムを作成してください。 パッケージ名は不要で、カレントディレクトリーに作成してください。 $1が指定されなかった場合は、`App.java`というファイル名にしてください。 プログラムを作成した後は、`java $1.java`コマンドで作成したプログラムを実行してください。
実行。
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── > /java-hello-world HelloWorld ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
ファイル作成の許可が求められます。
> /java-hello-world is running… HelloWorld
● Write(HelloWorld.java)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Create file
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ HelloWorld.java │
│ │
│ public class HelloWorld { │
│ public static void main(String[] args) { │
│ System.out.println("Hello World"); │
│ } │
│ } │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Do you want to create HelloWorld.java?
❯ 1. Yes
2. Yes, allow all edits during this session (shift+tab)
3. No, and tell Claude what to do differently (esc)
次に、Bashの使用許可が求められます。
● Bash(java HelloWorld.java) ⎿ Running… ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Bash command java HelloWorld.java Execute the Java program Do you want to proceed? ❯ 1. Yes 2. Yes, and don't ask again for java commands in /home/vagrant/sample-project 3. Tell Claude what to do differently
結果。
● Bash(java HelloWorld.java) ⎿ Hello World
よさそうです。
次に、ツールを指定して許可を求めないようにしてみましょう。WriteとBashを追加。
.claude/commands/java-hello-world.md
--- allowed-tools: Write, Bash argument-hint: [class-name] description: Hello Worldを出力するJavaプログラムを作成して実行します --- `$1.java`というファイルに、「Hello World」を出力するJavaプログラムを作成してください。 パッケージ名は不要で、カレントディレクトリーに作成してください。 $1が指定されなかった場合は、`App.java`というファイル名にしてください。 プログラムを作成した後は、`java $1.java`コマンドで作成したプログラムを実行してください。
実行すると、許可済みのツールを2つ使おうとしていることがわかります。
> /java-hello-world is running… HelloWorld2 ⎿ Allowed 2 tools for this command
結果。
● Write(HelloWorld2.java)
⎿ Wrote 5 lines to HelloWorld2.java
public class HelloWorld2 {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
● Bash(javac HelloWorld2.java && java HelloWorld2)
⎿ Hello World
● The Java program HelloWorld2.java was created and executed successfully. The output is:
Hello World
I'm marking the final todo as completed.
なんか微妙に指示を守っていませんね。少しプロンプトを変えて、さらにツールの制御を細かく指定してみました。
.claude/commands/java-hello-world.md
--- allowed-tools: Write, Bash(java:*) argument-hint: [class-name] description: Hello Worldを出力するJavaプログラムを作成して実行します --- `$1.java`というファイルに、「Hello World」を出力するJavaプログラムを作成してください。 パッケージ名は不要で、カレントディレクトリーに作成してください。 $1が指定されなかった場合は、`App.java`というファイル名にしてください。 プログラムを作成した後は、`java $1.java`コマンドで作成したプログラムを実行してください。 javacコマンドを使ったコンパイルは不要です。
結果。
> /java-hello-world is running… HelloWorld3
⎿ Allowed 2 tools for this command
● Write(HelloWorld3.java)
⎿ Wrote 5 lines to HelloWorld3.java
public class HelloWorld3 {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
● Bash(java HelloWorld3.java)
⎿ Hello World
OKですね。
さて、こちらの指定ですが
allowed-tools: Write, Bash(java:*)
指定方法はこのあたりに詳しく書かれています。
Identity and Access Management / Access control and permissions
デフォルトでは、ファイルの読み込みは許可は求めないものの、コマンドの実行やファイルの変更は許可を求めるようになっています。
Identity and Access Management / Access control and permissions / Permission system
Claude Codeで利用できるツールの一覧はこちら。
Claude Code settings / Tools available to Claude
そしてツール固有のルール指定について。
- Bash
Bash(npm run build)…npm run buildコマンドに完全一致Bash(npm run test:*)…npm run testで始まるコマンドに一致
- ReadおよびEdit
ファイルパス指定では、/は絶対パスではないんですね。またWriteはこのようなパス指定はできなさそうです(指定しても無視されました)。
java $.javaは前方一致する必要があるので、Bash(java:*)という指定になります。
今回は使っていませんが、MCPについてはワイルドカードをサポートしていないことに注意した方がよさそうです。
mcp__puppeteer… puppeteer MCPサーバーが提供するあらゆるツールにマッチするmcp__puppeteer__puppeteer_navigate… puppeteer MCPサーバーが提供するpuppeteer_navigateツールにマッチする
最後に、.claude/settings.jsonでの設定を引き継ぐことを確認してみます。
カスタムスラッシュコマンドからallowed-toolsを削除。
.claude/commands/java-hello-world.md
--- argument-hint: [class-name] description: Hello Worldを出力するJavaプログラムを作成して実行します --- `$1.java`というファイルに、「Hello World」を出力するJavaプログラムを作成してください。 パッケージ名は不要で、カレントディレクトリーに作成してください。 $1が指定されなかった場合は、`App.java`というファイル名にしてください。 プログラムを作成した後は、`java $1.java`コマンドで作成したプログラムを実行してください。 javacコマンドを使ったコンパイルは不要です。
settings.jsonで許可するツールを設定。
.claude/settings.json
{ "permissions": { "allow": [ "Write", "Bash(java:*)" ] } }
これでも先ほどと同じように動作します。
> /java-hello-world is running… HelloWorld
● Write(HelloWorld.java)
⎿ Wrote 5 lines to HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
● Bash(java HelloWorld.java)
⎿ Hello World
こんなところでしょうか。
おわりに
Claude Codeのカスタムスラッシュコマンドを試してみました。
なんとなく雰囲気はわかっていたつもりだったのですが、ドキュメントを見ながらしっかりやると理解が進みますね。
引き続き他のテーマも見ていこうと思います。