Slash Command 上級編:コンテキストを読み取る指令を作る

! プレフィックスで shell コマンドを実行し、diff・ファイル内容・テスト結果を自動注入して Claude に曖昧な説明でなく実際の情報を渡す


ほとんどの人の slash command はこんな感じだ:

現在の変更のコード品質をレビューし、具体的な提案を出して。

これでも動くが、根本的な制約がある:Claude は「現在の変更とは何か」を自分で推測しなければならない。command が能動的にコンテキストを注入できれば、結果はまったく違ったものになる。

この記事では、command を「目を持った」指令に変える方法を扱う——トリガー時にファイルの内容、git の状態、プロジェクト情報を自動で読み取り、それらをプロンプトに埋め込むことで、Claude に推測させない。


コアメカニズム:!`コマンド` で Shell 出力を注入

カスタム slash command はプロンプトの中に shell コマンドを埋め込めるようになっており、構文はバッククォートでコマンドを囲み、その前にエクスクラメーションマークを付ける:!`コマンド`。トリガー時にコマンドが先に実行され、出力がプレースホルダを置き換え、Claude が受け取るのは最終的に組み立てられたプロンプトになる。

以下が現在の git diff です:

!`git diff HEAD`

これらの変更をレビューし、ロジックエラーとセキュリティ問題に重点を置いてください。

複数行のコマンドはフェンスドコードブロック形式で、先頭に ```! と書く:

```!
node --version
git status --short
```

/review をトリガーした時、Claude が実際に受け取る内容はこうなる:

以下が現在の git diff です:

diff --git a/app/models/user.rb b/app/models/user.rb
index 3a2f1c8..9b4e2d1 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -12,6 +12,9 @@ class User < ApplicationRecord
...

これらの変更をレビューし、ロジックエラーとセキュリティ問題に重点を置いてください。

手動でコピー&ペーストする必要はない。command がトリガーされた瞬間、diff はすでに中に入っている。


実用パターン

現在のファイルの内容を注入する

---
allowed-tools: Bash(cat:*)
---

以下が現在のファイルの完全な内容です:

!`cat $ARGUMENTS`

このファイル内の潜在的なパフォーマンス問題をすべて見つけ出し、具体的な行番号と修正方法を示してください。

使い方:/perf app/models/order.rb

$ARGUMENTS がファイルパスを受け取り、cat が内容を読み込んで注入する。Claude が受け取るのは実際のコードであって、「現在のファイルを見てください」といった曖昧な記述ではない。

allowed-tools は frontmatter で cat コマンドを事前承認しており、トリガー時に権限確認が出ない。この行がないと、実行のたびに「許可」を手動でクリックする必要がある。以下の例も同じ方法で宣言する必要がある。

git の状態を注入する

現在のブランチと変更状況:

!`git status --short`
!`git log --oneline -10`

以上の情報をもとに、変更内容と動機を含む簡潔な PR 説明を生成してください。

この /pr command は「自分が何を変えたか」を記述する必要がない。command 自身が読みに行く。

プロジェクト固有の情報を注入する

プロジェクトの技術スタック:

!`cat .claude/context/stack.md`

現在のデータベース構造(主要テーブル):

!`head -100 db/schema.rb`

以上を踏まえて、$ARGUMENTS のためにプロジェクト規約に沿ったマイグレーションスクリプトを書いてください。

プロジェクトの背景情報を事前に .claude/context/ ディレクトリに書いておき、command がトリガーされた時に必要に応じて読み取る。プロジェクトの状況を毎回繰り返し説明する必要がない。

テスト結果を動的に読み込む

最新のテスト実行結果:

!`bundle exec rspec --format progress 2>&1 | tail -30`

以上が失敗したテストです。根本原因を分析し、修正案を出してください。テスト自体は変更しないでください。

/fix-tests がトリガーされた時、直接テストを走らせて結果を取得する。Claude が見るのは実際のエラーメッセージだ。


完全な例:コンテキスト対応のコードレビュー

ここまでを組み合わせると、/review はかなり精度の高いものになる:

---
description: 現在の変更をレビューし、diff と関連する背景を自動注入する
allowed-tools: Bash(git diff:*), Bash(cat:*)
---

## 今回の変更

!`git diff HEAD`

## 変更されたファイル一覧

!`git diff HEAD --name-only`

## プロジェクトのコーディング規約サマリー

!`cat .claude/context/coding-standards.md 2>/dev/null || echo "(規約ファイルなし)"`

---

以上の変更をレビューしてください:

1. ロジックの正しさ:未処理の境界条件やロジックエラーがないか
2. セキュリティ問題:SQL インジェクション、権限チェック、機密情報の露出
3. 規約適合性:プロジェクトのコーディング規約に沿っているか
4. 可読性:命名、コメント、構造

各問題について、ファイル名、行番号、具体的な提案を示してください。問題がなければないと言ってください、水増ししないように。

この command はこちらの準備をまったく必要としない——トリガーされた瞬間、diff、ファイル一覧、コーディング規約がすべて自動注入される。


コマンド失敗時の処理

Shell コマンドは失敗することがある(ファイルがない、コマンドが PATH にないなど)。|| でデフォルト値を用意して、command が中断しないようにする:

!`git diff HEAD 2>/dev/null || echo "(git の変更なし、または git リポジトリ内ではない)"`
!`cat .env.example 2>/dev/null || echo "(.env.example ファイルなし)"`
!`which rspec > /dev/null 2>&1 && bundle exec rspec --dry-run 2>&1 | head -20 || echo "(RSpec が検出されません)"`

コマンドが失敗した時、Claude は空白ではなく説明文を受け取り、それに応じて回答戦略を調整できる。


パフォーマンスへの配慮:注入しすぎない

! コマンドの出力はすべて context window に入る。よくある落とし穴をいくつか:

大きなファイル全体を cat しない

# 危険:数万行注入される可能性がある
!`cat db/schema.rb`

# より良い:必要な部分だけ取る
!`grep -A 5 "create_table \"orders\"" db/schema.rb`

ログファイルには行数制限を

!`tail -50 log/development.log`

テスト出力の切り詰め

!`bundle exec rspec 2>&1 | tail -40`

context が精密であるほど、Claude の回答は良くなる。コードベース全体を詰め込んでも賢くなるわけではなく、ノイズの中で迷うだけだ。


CLAUDE.md との分担

よくある質問:プロジェクトの背景情報は CLAUDE.md に置くべきか、それとも ! で動的注入すべきか?

判断基準:

情報の種類 どこに置くか
毎回必要なプロジェクト背景(技術スタック、ディレクトリ構造、規約) CLAUDE.md
時間とともに変化する状態(現在の diff、テスト結果、ファイル内容) ! で動的注入
特定タスクでのみ必要な背景(あるモジュールの設計説明) !cat で必要に応じて読む

CLAUDE.md は永続的な背景知識、! はタスク時の即時スナップショット。両者は補完関係にあり、重複させないこと。


完全な .claude/commands/ ディレクトリ

.claude/
├── commands/
│   ├── review.md        # レビュー:diff + 規約を注入
│   ├── test.md          # テスト作成:対象ファイルを注入
│   ├── fix-tests.md     # テスト修正:失敗結果を注入
│   ├── pr.md            # PR 説明:git log + status を注入
│   ├── explain.md       # コード解説:ファイル内容を注入
│   └── migrate.md       # マイグレーション作成:schema の断片を注入
├── context/
│   ├── stack.md         # 技術スタックの説明
│   └── coding-standards.md  # コーディング規約
└── settings.json

context/ ディレクトリには静的な背景ファイルを置き、各 command が必要に応じて読み込む。この構造はそのまま git にコミットして、チームで共有できる。


効果の比較

静的な command

現在のコード変更をレビューしてください。

Claude は「変更はどこですか」と聞き返すか、自分で探しに行くことになり、結果は安定しない。

コンテキスト対応の command

これが diff(実際の内容付き)、これが関連規約(実際の内容付き)です、レビューしてください。

Claude はそのまま分析を始める。回答は精密で、無駄話がなく、やり取りも要らない。

差が出るのは Claude の能力ではなく、こちらがどれだけ実際の情報を渡したかだ。