TL;DR: Claude Code Hooks を使うと、ツール実行前後・タスク完了時に任意のスクリプトを自動実行できます。本記事では
PreToolUseで危険コマンドをブロック、PostToolUseで自動フォーマット、Notificationで Slack 通知する3パターンの実装例を解説します。
はじめに
本記事は Claude Code セットアップ2026 シリーズの一部です。インストールや基本設定を済ませた後に、Hooks で自動化を追加していく手順を解説します。
Claude Code を日常利用していると、次のような不満が出てきます。
- コード生成後に毎回手動で
prettierを回す手間 - AI が
rm -rfなどの危険なコマンドを実行しないか心配 - 長時間タスクが終わっても気づくのが遅れる
これらはすべて Claude Code Hooks で解決できます。Hooks は Claude Code のツール実行ライフサイクルに割り込める公式機能です(公式ドキュメント)。
本記事では、フック種別の概念整理から実際に動くスクリプト実装まで、すぐ使える形で提供します。
Claude Code Hooks とは
Hooks は ~/.claude/settings.json またはプロジェクト直下の .claude/settings.json に設定し、Claude Code のツール呼び出しライフサイクルの特定タイミングで任意のシェルコマンドを実行する仕組みです。
フック種別一覧
| フック種別 | 実行タイミング | 主なユースケース |
|---|---|---|
PreToolUse | ツール実行前 | 危険コマンドのブロック、実行ログ記録 |
PostToolUse | ツール実行後 | コードフォーマット、差分チェック |
Notification | Claude が通知を送るとき | Slack/メール通知、デスクトップ通知 |
Stop | セッション終了時 | 完了レポート生成、クリーンアップ |
フックの実行フロー
Claude がツール呼び出しを決定
↓
[PreToolUse フック] ← exit 2 でブロック可能
↓
ツール実行(Bash, Write, Edit など)
↓
[PostToolUse フック]
↓
Claude が次のアクションを決定
PreToolUse フックが exit 2 で終了すると、Claude はそのツール呼び出しをキャンセルし、代替アクションを検討します。それ以外の非ゼロ終了コードはエラー扱いになり、フックの stderr が Claude に伝わります(公式仕様)。
settings.json の書き方
Hooks は settings.json の hooks キーに設定します。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/safety.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/format.sh"
}
]
}
],
"Notification": [
{
"hooks": [
{
"type": "command",
"command": ".claude/hooks/notify-slack.sh"
}
]
}
]
}
}
設定の優先順位
- プロジェクト直下の
.claude/settings.jsonがグローバル(~/.claude/settings.json)より優先(公式値) - チームで共有する場合はプロジェクト設定をリポジトリに含め、個人設定はグローバルに置く
ユースケース1: 自動フォーマット(PostToolUse)
ファイルを書き換えるたびに Prettier を自動実行します。本リポジトリでも .claude/hooks/format.sh として実際に運用しています(経験則)。
#!/usr/bin/env bash
# .claude/hooks/format.sh
set -euo pipefail
if ! command -v pnpm >/dev/null 2>&1; then
echo "[format] pnpm not found, skipping"
exit 0
fi
if [ ! -d .git ]; then
echo "[format] Not a git repository, skipping"
exit 0
fi
# 変更されたファイルを取得(-z で空白ファイル名も安全に処理)
git diff -z --name-only --diff-filter=ACMRTUXB HEAD 2>/dev/null \
| while IFS= read -r -d '' file; do
case "$file" in
*.js|*.jsx|*.ts|*.tsx|*.json|*.md|*.yml|*.yaml|*.mjs)
if [ -f "$file" ]; then
pnpm exec prettier --write "$file" || true
fi
;;
esac
done
echo "[format] Done"
settings.json への追記
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{ "type": "command", "command": ".claude/hooks/format.sh" }
]
}
]
matcher は正規表現が使えます。Write|Edit|MultiEdit はファイル書き換え系の3ツールすべてにマッチします。
ユースケース2: 危険コマンドガード(PreToolUse)
rm -rf や git reset --hard など取り消し不能な操作を自動ブロックします。本リポジトリでも .claude/hooks/safety.sh として運用中です(経験則)。
#!/usr/bin/env bash
# .claude/hooks/safety.sh
set -euo pipefail
# CLAUDE_TOOL_INPUT 環境変数から実行予定コマンドを取得(公式値)
tool_input="${CLAUDE_TOOL_INPUT:-}"
if [ -z "$tool_input" ] && [ ! -t 0 ]; then
tool_input="$(cat)"
fi
# JSON からコマンド文字列を抽出
command_str=""
if [ -n "$tool_input" ] && command -v node >/dev/null 2>&1; then
command_str="$(printf '%s' "$tool_input" \
| node -e 'const d=JSON.parse(require("fs").readFileSync(0,"utf8"));
if(d&&typeof d.command==="string") process.stdout.write(d.command);'
)"
fi
if [ -z "$command_str" ]; then
exit 0
fi
command_lc="$(printf '%s' "$command_str" | tr 'A-Z' 'a-z')"
# ブロックするパターン一覧
danger_patterns=(
"rm -rf"
"rm -fr"
"git reset --hard"
"git clean -fd"
"git clean -fdx"
"kubectl delete"
"docker system prune"
"mkfs"
"dd if="
"shutdown"
"reboot"
)
for pattern in "${danger_patterns[@]}"; do
if [[ "$command_lc" == *"$pattern"* ]]; then
echo "[safety] Blocked: $pattern" >&2
echo "[safety] Command: $command_str" >&2
exit 2 # exit 2 でツール呼び出しをキャンセル
fi
done
exit 0
ポイント
exit 2を返すと Claude はそのコマンドをキャンセルし、代替策を考えます(公式値)- stderr に出力した内容は Claude に伝わるため、ブロック理由を明記すると Claude が適切に対処します
CLAUDE_TOOL_INPUT環境変数にはツールの JSON 引数が渡されます(公式値)
ユースケース3: Slack 通知(Notification)
長時間タスクの完了を Slack に通知します。
#!/usr/bin/env bash
# .claude/hooks/notify-slack.sh
set -euo pipefail
SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:-}"
if [ -z "$SLACK_WEBHOOK_URL" ]; then
echo "[notify] SLACK_WEBHOOK_URL not set, skipping"
exit 0
fi
# CLAUDE_NOTIFICATION_MESSAGE 環境変数に通知メッセージが入る(公式値)
message="${CLAUDE_NOTIFICATION_MESSAGE:-Claude Code: タスクが完了しました}"
project_dir="$(pwd | xargs basename)"
payload="{
\"text\": \"*[${project_dir}]* ${message}\",
\"username\": \"Claude Code\",
\"icon_emoji\": \":robot_face:\"
}"
curl -s -X POST \
-H 'Content-Type: application/json' \
-d "$payload" \
"$SLACK_WEBHOOK_URL" \
> /dev/null
echo "[notify] Sent to Slack"
Webhook URL の管理
Webhook URL はコードに直書きせず、環境変数で渡してください。.env ファイルや OS のキーチェーンに保存し、シェルの起動スクリプト(~/.zshrc 等)で export SLACK_WEBHOOK_URL=... しておく方法が一般的です(経験則)。
settings.json への追記
"Notification": [
{
"hooks": [
{ "type": "command", "command": ".claude/hooks/notify-slack.sh" }
]
}
]
Notification フックには matcher は不要です。Claude が通知を送るたびに実行されます。
ユースケース4: Stop フックで完了レポート生成
セッション終了時に変更ファイル一覧を記録します。
#!/usr/bin/env bash
# .claude/hooks/session-report.sh
set -euo pipefail
report_dir=".claude/session-reports"
mkdir -p "$report_dir"
timestamp="$(date +%Y%m%d-%H%M%S)"
report_file="${report_dir}/${timestamp}.txt"
{
echo "=== Claude Code Session Report: $(date) ==="
echo ""
echo "--- Git Status ---"
git status --short 2>/dev/null || echo "(not a git repo)"
echo ""
echo "--- Changed Files ---"
git diff --name-only HEAD 2>/dev/null || true
} > "$report_file"
echo "[session-report] Saved to $report_file"
"Stop": [
{
"hooks": [
{ "type": "command", "command": ".claude/hooks/session-report.sh" }
]
}
]
チームでの運用パターン
複数人で hooks を共有する場合は次の構成を推奨します。
.claude/
settings.json # チーム共通設定(リポジトリに含める)
hooks/
format.sh # 自動フォーマット
safety.sh # 危険コマンドガード
notify-slack.sh # Slack 通知
session-report.sh # 完了レポート
settings.json をリポジトリに含める際の注意
- Webhook URL などの秘匿情報はコミットしない
- 秘匿情報は環境変数経由でスクリプトに渡す
- スクリプトに
chmod +xを忘れずに設定する(git update-index --chmod=+x .claude/hooks/*.shでパーミッション管理可能)
個人カスタマイズ
チーム設定をベースに個人用の追加フックを入れたい場合は ~/.claude/settings.json のグローバル設定に追記します。プロジェクト設定とグローバル設定は両方が適用され、同一イベントに複数フックがあればすべて実行されます(公式仕様)。
やりがちな失敗とデバッグ
フックが実行されない
原因と対処法
- スクリプトに実行権限がない →
chmod +x .claude/hooks/*.shを実行 - settings.json の JSON が壊れている →
python3 -m json.tool .claude/settings.jsonでバリデーション - matcher が一致していない → matcher は正規表現。
"Bash"はツール名 Bash に部分一致する
PreToolUse で exit 2 したのに止まらない
exit 2 が有効なのは PreToolUse のみです。PostToolUse で exit 2 しても動作に影響しません。また、フック自体がクラッシュするとツール実行はブロックされません。安全ガードとして使う場合は set -euo pipefail でエラーを確実に検知してください。
デバッグ方法
# フックを手動実行してデバッグ
CLAUDE_TOOL_INPUT='{"command": "rm -rf /tmp/test"}' bash .claude/hooks/safety.sh
# settings.json のバリデーション
python3 -m json.tool .claude/settings.json
フック種別 × ユースケース 対応マトリクス
| ユースケース | PreToolUse | PostToolUse | Notification | Stop |
|---|---|---|---|---|
| 危険コマンドブロック | ✓ | - | - | - |
| 自動フォーマット | - | ✓ | - | - |
| 差分チェック | - | ✓ | - | - |
| Slack/メール通知 | - | - | ✓ | - |
| 完了レポート生成 | - | - | - | ✓ |
| クリーンアップ | - | - | - | ✓ |
| 実行ログ記録 | ✓ | ✓ | - | - |
まとめ
Claude Code Hooks は少ない設定で大きな自動化効果が得られます。
- PreToolUse: 危険コマンドを
exit 2でブロック - PostToolUse: ファイル変更後に自動フォーマット
- Notification: タスク完了を Slack に通知
- Stop: セッション終了時にレポート生成
まずは format.sh と safety.sh の2本から始めて、チームの運用に合わせて拡張していくことをお勧めします。
Claude Code を活用した開発フロー全般についてはAIペアプログラミングのパターン集も参照してください。MCP を使ったさらなる拡張についてはMCP プロトコル実装ガイドで詳しく解説しています。書いた hook が本当に効いているか(permission rule との評価順序を含む)を検証する手順はAIガバナンスが効かない4類型と検証手順にまとめています。
このシリーズについて
本記事は「Claude Code セットアップ2026」シリーズの一部です。シリーズ全体は Claude Code セットアップ2026 からご覧いただけます。インストールから CLAUDE.md・Hooks・MCP・失敗パターンまで体系的に解説しています。
FAQ
Claude Code Hooks とは何ですか?
Claude Code Hooks は、Claude Code のツール実行ライフサイクル(実行前・実行後・通知時・セッション終了時)に任意のシェルスクリプトを自動実行できる公式機能です。settings.json に設定するだけで利用できます(公式ドキュメント)。
PreToolUse と PostToolUse の違いは何ですか?
PreToolUse はツール実行前に動き、exit 2 を返すことでツール実行をキャンセルできます。PostToolUse はツール実行後に動き、実行結果に対して後処理(フォーマットなど)を行います。
危険なコマンドを自動でブロックするにはどうすれば良いですか?
PreToolUse フックに matcher: "Bash" を設定し、スクリプト内で CLAUDE_TOOL_INPUT 環境変数からコマンド文字列を取り出してパターンマッチし、危険なパターンに一致したら exit 2 で終了します。本記事の safety.sh サンプルをそのままコピーして使えます。
Claude Code で Slack 通知を送るにはどうすれば良いですか?
Notification フックに Slack Webhook URL へ curl で POST するスクリプトを設定します。CLAUDE_NOTIFICATION_MESSAGE 環境変数に通知メッセージが入るため、そのまま Slack のペイロードに含めることができます。
hooks の設定は settings.json のどこに書きますか?
.claude/settings.json(プロジェクト設定)または ~/.claude/settings.json(グローバル設定)の hooks キー配下に書きます。プロジェクト設定の方がグローバル設定より優先されますが、同一イベントに設定がある場合は両方が実行されます(公式仕様)。
References
- Claude Code Hooks 公式ドキュメント(Anthropic 公式)
- Claude Code 設定リファレンス(Anthropic 公式)
- Claude Code の概要(Anthropic 公式)
- AIペアプログラミングのパターン集
- MCP プロトコル実装ガイド
- AI 駆動開発プランニング
