要約
入門編では Hooks の基本概念と3つの実例を紹介した。本記事(基礎編)では、日常開発で頻繁に使うユースケースを具体的な活用事例と設定方法で解説する。
Chrome 拡張の自動ビルド、TDD の強制、自動 Lint/Format、API スモークテスト、Slack 通知、重複コード検出、Skill 自動選択まで——ここまで読めば Hooks を日常的に使いこなせるようになる。
対象読者: 入門編を読み終え、Hooks の基本構造を理解した開発者。より実践的なフックを自分のプロジェクトに導入したい方。
この記事を読むことで得られるメリット
この記事を読むことで以下のことが分かる:
- Chrome 拡張開発での自動ビルド + ZIP + 説明文整合性チェックのワークフローを構築できる
- TDD の強制、自動 Lint/Format など品質保証の自動化パターンを把握できる
- API スモークテストの2つの実装パターンを比較して使い分けられる
- Slack 通知や TTS 音声通知の具体的な実装方法を知る
- PostToolUse vs Stop の使い分けや
async: true、additionalContextなどの実践 Tips を得られる - 主要イベントとマッチャーの早見表を手元に置ける
この記事を読むのにかかる時間
約25分
環境
- Claude Code 2.0.65+
- macOS / Linux
- jq がインストール済みであること
なぜ具体的な活用事例を学ぶのか
入門編で Hooks の概念と仕組みを理解した。しかし、概念を知っているだけでは実務での有効活用にはつながらない。
「PostToolUse で Edit|Write を検知する」と知っていても、それを自分のプロジェクトでどう使うかが分からなければ意味がない。本記事では具体的な活用事例と設定方法を通じて、Hooks の実践的な使い方を解説する。
品質保証の自動化
Chrome 拡張開発での自動ビルド
筆者が実際に運用している事例である。Chrome 拡張機能の開発プロジェクトで、ソースコードの編集後にビルドとストア提出用 ZIP の生成を自動化している。さらに、Stop フックで agent タイプを使い、manifest.json の permissions と description がストア説明文(store-listing.md)と一致しているかも自動検証する。
.claude/hooks/post-edit.sh:
#!/bin/bash
set -e
echo "Building extension..."
npm run build
echo "Creating zip archive..."
cd dist && zip -r ../extension.zip . && cd ..
echo "Build and zip completed successfully!".claude/settings.local.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/post-edit.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "manifest.json の permissions と description が store-listing.md の説明文と一致しているか検証せよ。$ARGUMENTS"
}
]
}
]
}
}set -e を指定しているため、npm run build が失敗した時点でスクリプトが終了し、Claude にエラーが伝わる。これにより**「コードは書いたがビルドが通らない状態で完了を宣言する」ことを防止**できる。
TDD Guard — テスト駆動開発の強制
nizos/tdd-guard は Claude Code に TDD を強制するプラグインである。
仕組み:
- Claude が実装コード(テストファイル以外)を変更しようとする
- PreToolUse フックが現在のテストスイートを確認
- 失敗するテストが存在しない状態で実装コードを追加しようとした場合 →
exit 2でブロック - 「先にテストを書いてください」と促す
Vitest、Jest、Storybook、pytest、PHPUnit、Go、Rust の7フレームワークに対応している。
自動 Lint/Format
Claude がファイルを編集した直後に Prettier を自動実行し、フォーマットを統一する。
.claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write 2>/dev/null || true"
}
]
}
]
}
}言語別に分岐する場合:
#!/bin/bash
FILE_PATH=$(jq -r '.tool_input.file_path')
if [[ "$FILE_PATH" == *.py ]]; then
black --quiet "$FILE_PATH" 2>/dev/null
elif [[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.ts ]]; then
npx prettier --write "$FILE_PATH" 2>/dev/null
fiコンテキスト消費に注意: PostToolUse でフォーマッターがファイルを変更すると、Claude Code がファイル内容を system reminder としてコンテキストに自動注入する。3ラウンドで160kトークンを消費するケースも報告されている(出典: ksred.com、rosmur.github.io、GitHub Issue #4464)。
推奨される代替手段:
- エディタの Format On Save で十分なケースが多い
- pre-commit フック(husky + lint-staged 等)でコミット時にフォーマット
- どうしても Hooks でやる場合は、PostToolUse ではなく Stop フックでコミット時にバッチ処理する
手動テストケースの更新漏れ検知
筆者が実際に運用している事例である。手動テストケース(Markdown ファイル)をスキルで作成した後、実装コードが変更されたタイミングで対応するテストケースの更新が必要かを自動検知する。
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# 実装ファイル以外はスキップ
if [[ "$FILE_PATH" != */src/* ]]; then
exit 0
fi
# 対応するテストケースファイルを探す
BASENAME=$(basename "$FILE_PATH" | sed 's/\.[^.]*$//')
TEST_FILE="$CLAUDE_PROJECT_DIR/tests/manual/${BASENAME}.md"
if [[ -f "$TEST_FILE" ]]; then
cat <<EOF
{"additionalContext": "Warning: ${FILE_PATH} に対応する手動テストケース ${TEST_FILE} が存在します。実装の変更に伴い、テストケースの更新が必要な可能性があります。"}
EOF
fi
exit 0exit 2 でブロックするのではなく additionalContext で注意喚起にとどめているのがポイントである。テストケースの更新が常に必要とは限らないため、Claude に判断を委ねている。
デプロイ確認ページの自動オープン
筆者が実際に運用している事例である。Claude の作業完了時に Vercel のデプロイメントページをブラウザで自動的に開く。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "open https://vercel.com/<user>/<project>/deployments"
}
]
}
]
}
}非常にシンプルだが効果的。open コマンド(macOS)一行で、「作業は終わったがデプロイ結果を見忘れる」という日常的な問題を確実に防止できる。Vercel 以外にも Netlify、GitHub Actions、PR ページなど、open の URL を変えるだけで応用可能。
API エンドポイントの自動疎通確認
API 開発中、Claude にルート追加やハンドラ修正を依頼すると、コードは書かれるがレスポンスの実動作を確認しないまま「完了」を宣言することがある。2つの実装パターンを紹介する。
パターン A: Stop フックで完了前に全エンドポイントをチェック
#!/bin/bash
INPUT=$(cat)
# Stop Hook の再帰防止
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0
fi
BASE_URL="http://localhost:3000"
ENDPOINTS=(
"GET /api/health 200"
"GET /api/users 200"
"POST /api/auth/login 401"
)
FAILURES=()
for endpoint in "${ENDPOINTS[@]}"; do
METHOD=$(echo "$endpoint" | awk '{print $1}')
URL_PATH=$(echo "$endpoint" | awk '{print $2}')
EXPECTED=$(echo "$endpoint" | awk '{print $3}')
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X "$METHOD" "${BASE_URL}${URL_PATH}" 2>/dev/null)
if [ "$STATUS" != "$EXPECTED" ]; then
FAILURES+=("${METHOD} ${URL_PATH}: expected ${EXPECTED}, got ${STATUS}")
fi
done
if [ ${#FAILURES[@]} -gt 0 ]; then
echo "API疎通チェック失敗:" >&2
for f in "${FAILURES[@]}"; do
echo " x $f" >&2
done
exit 2
fi
exit 0重要: Stop フックの再帰防止。
stop_hook_activeチェックを入れないと、フックが失敗 → Claude が修正 → 再度 Stop → フック実行... の無限ループに陥る可能性がある。
パターン B: PostToolUse でルートファイル変更時に即座確認
API ルートファイル(/routes/、/api/、controller を含むパス)が変更されたタイミングでピンポイントに疎通チェックする。サーバー未起動時はブロックせずスキップし、additionalContext で注意喚起にとどめる。
.claude/hooks/api-route-check.sh:
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# API ルートファイル以外はスキップ
if [[ "$FILE_PATH" != *"/routes/"* ]] && [[ "$FILE_PATH" != *"/api/"* ]] && [[ "$FILE_PATH" != *"controller"* ]]; then
exit 0
fi
BASE_URL="http://localhost:3000"
# 開発サーバーが起動していなければスキップ
if ! curl -s -o /dev/null --max-time 2 "${BASE_URL}/api/health" 2>/dev/null; then
echo '{"additionalContext": "Warning: 開発サーバー未起動のため API 疎通チェックをスキップしました。サーバーを起動してテストすることを推奨します。"}'
exit 0
fi
# 変更ファイルからエンドポイントパスを推定
ROUTE_NAME=$(basename "$FILE_PATH" | sed 's/\.\(ts\|js\|py\)$//')
TEST_PATH="/api/${ROUTE_NAME}"
STATUS=$(curl -s -o /tmp/api-response.json -w "%{http_code}" --max-time 5 "${BASE_URL}${TEST_PATH}" 2>/dev/null)
BODY=$(cat /tmp/api-response.json 2>/dev/null | head -c 500)
if [ "$STATUS" -ge 500 ]; then
cat <<EOF
{"additionalContext": "Error: API疎通チェック: ${TEST_PATH} がステータス ${STATUS} を返しました。\nレスポンス: ${BODY}\n修正してください。"}
EOF
elif [ "$STATUS" -ge 400 ]; then
cat <<EOF
{"additionalContext": "Warning: API疎通チェック: ${TEST_PATH} がステータス ${STATUS} を返しました(認証が必要な場合は正常)。\nレスポンス: ${BODY}"}
EOF
else
cat <<EOF
{"additionalContext": "OK: API疎通チェック: ${TEST_PATH} -> ${STATUS} OK"}
EOF
fi
exit 0ファイル名からエンドポイントを推定し、ステータスコードに応じて additionalContext でフィードバックを返す。サーバー未起動時はブロックせずスキップする設計がポイントである。
通知・フィードバック
Slack Webhook 通知
Claude が作業を完了した際に Slack チャンネルに通知を送る。長時間タスクを実行中に離席していても、完了を把握できる(出典: kenfdev)。
#!/bin/bash
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
INPUT=$(cat)
MESSAGE=$(echo "$INPUT" | jq -r '.message // "Task completed"')
curl -s -X POST "$WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d "{\"attachments\":[{\"color\":\"#36a64f\",\"title\":\"Claude Code\",\"text\":\"$MESSAGE\"}]}"HTTP 型フック(type: "http")を使えば、シェルスクリプトなしでも直接 Webhook に POST できる。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "http",
"url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
}
]
}
]
}
}AI 生成音声によるタスク完了通知(TTS)
disler/claude-code-hooks-mastery(約3.4K stars)は、Stop イベント時に LLM でタスクサマリーを生成し、TTS で読み上げる。OpenAI → Anthropic → Ollama の優先順で利用可能な LLM を自動選択する仕組み。
macOS であれば say コマンドで簡易的な TTS 通知も実現できる。
重複コード検出フック
PostToolUse でコードベースの類似性をインデクサーでチェックし、既に存在する機能の重複実装を防止する。
仕組み:
- Claude が Edit/Write でコードを追加する
- PostToolUse でコードベース内の類似コードを検索
additionalContextで「既存の実装が存在する」ことを通知し、重複ではなく既存コードの再利用を促す
ブロック(exit 2)ではなく additionalContext でフィードバックを返す設計である。例: "src/utils/format.ts に類似の formatDate() が既にあります。新規実装の前に再利用を検討してください"(出典: Hacker News)。
Skill 自動評価・選択
UserPromptSubmit フックでユーザー入力のキーワード・意図パターンを分析し、適用すべき Skill を自動選択してコンテキストに注入する。
仕組み:
- ユーザーがプロンプトを送信
- UserPromptSubmit フックがキーワード・ファイルパス・意図パターンを分析
additionalContextで最適な Skill を注入
通常、Skills は Claude の判断でマッチングされるが、タスクに集中している場合にスキップされることがある。このフックによりプロンプト送信時に確実に適切な Skill が有効化される。ChrisWiles/claude-code-showcase で実装が公開されている。
実践 Tips
PostToolUse vs Stop の使い分け
観点 | PostToolUse | Stop |
|---|---|---|
タイミング | ツール実行直後 | ターン完了時 |
用途 | ビルド確認・即座フィードバック | 通知・コミット・最終検証 |
頻度 | 高(毎ツール呼び出し) | 低(ターンごと) |
コンテキスト消費 | 高(ファイル変更は再注入される) | 低 |
推奨: 検知は PostToolUse、バッチ処理や最終チェックは Stop フックで行うのが実務上のベストプラクティス。
async: true でバックグラウンド実行
結果を待つ必要がないフック(ログ記録、通知等)は "async": true を設定すると、Claude の作業をブロックせずにバックグラウンドで実行される。応答速度を維持しつつサイドエフェクトを実行できる。
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/audit-log.sh",
"async": true
}additionalContext でフィードバック注入
フックの出力 JSON に additionalContext キーを含めると、Claude のコンテキストに文字列として注入される。ブロックせずに情報を渡したい時に使う。
echo '{"additionalContext": "Warning: この変更に対応するテストケースの更新が必要な可能性があります。"}'
exit 0exit 2 でブロックするほどではないが Claude に認識させたい情報がある場合に有効である。
CLAUDE.md との併用
ルールは CLAUDE.md で事前に指示し、強制は Hooks で実行する。二重の安全網を構築することで、Claude がブロックされる前に正しい手順を選択する確率を上げつつ、最終防衛線として確実にブロックできる。
Hooks イベント早見表
全23イベントから主要7種をセッションのライフサイクル順に紹介する。
イベント | タイミング | 主な用途 | async対応 |
|---|---|---|---|
| セッション開始 | ルール再注入・環境チェック | - |
| プロンプト送信時 | Skill自動選択・入力検証 | - |
| ツール実行前 | 実行ブロック・バリデーション | - |
| ツール実行後 | ビルド確認・ログ記録 | 対応 |
| 通知発生時 | Slack/Discord連携 | 対応 |
| ターン完了時 | 通知・コミット・PDF生成 | - |
| セッション終了 | ログ保存・クリーンアップ | 対応 |
他にも PreCompact / SubagentStop / ConfigChange / PermissionRequest 等、計23種のイベントがある。全イベントの一覧は応用編の付録を参照。
マッチャーパターン早見表
matcher でフックの発火条件をフィルタリングする。正規表現で指定する。
イベント | マッチ対象 | マッチャー例 |
|---|---|---|
| 開始方法 |
|
| - | マッチャー非対応(常に全出現で発火) |
| ツール名 |
|
| 通知タイプ |
|
| 終了理由 |
|
よく使うツール名マッチャー: Bash, Edit, Write, Read, Glob, Grep, WebFetch, Agent
正規表現の活用: Edit|Write で複数ツールを OR マッチ。mcp__.* で全 MCP ツールにマッチ。
まとめ
- 品質保証: Chrome 拡張ワークフロー、TDD Guard、自動 Lint/Format、テスト漏れ検知、API スモークテストで品質を自動化
- 通知: Slack Webhook や TTS で Claude の状態を常に把握する
- コード品質: 重複コード検出と Skill 自動選択で開発効率を向上
- 実践 Tips: PostToolUse と Stop の使い分け、
async: true、additionalContextを適切に活用する - コンテキスト消費: PostToolUse でファイル変更するフックはコンテキストを消費するため、Stop フックでのバッチ処理を検討する
応用編では、仕様駆動開発でのドリフト検出、監査ログ、セキュリティ(秘匿情報防御・ファイル保護)、Git 連携、そして Hooks 自体のセキュリティリスクと落とし穴を扱う。
関連記事
参考リンク
- 公式ドキュメント: Hooks reference
- 公式ドキュメント: Automate workflows with hooks
- nizos/tdd-guard — TDD 強制プラグイン
- disler/claude-code-hooks-mastery — 全イベントの参照実装
- ChrisWiles/claude-code-showcase — Skill 自動選択