Claude Code のパーミッション設定(settings.json)だけでは対応しきれない細かい制御や、ツール実行前後の自動処理を実現したい——そんなときに使えるのが Hooks(フック) です。
Hooks を使いこなすことで、Claude Code を「監視・制御できる AI エージェント」へと昇格させることができます。本記事では、フックの種別・設定方法・実践的な活用パターンまでを体系的に解説します。
[目次を開く]
Hooks とは?
一言で言うと
Hooks とは、Claude Code がツールを実行する前後に、カスタムのシェルスクリプトを自動実行する仕組みです。
たとえば以下のようなことが実現できます。
-
.envファイルへのアクセスを試みたとき、より細かい条件でブロックする - ツール実行のログをファイルに記録する
- 特定のファイルが編集されたら Slack に通知する
- コミット前に自動テストを走らせる
settings.json のパーミッションとの違い
settings.json の deny ルールは「ツール呼び出しをブロックする」シンプルな制御です。一方 Hooks は、実行前後に任意のスクリプトを走らせ、終了コードで許可・拒否を制御できるより高度な仕組みです。
| 機能 | settings.json パーミッション | Hooks |
|---|---|---|
| 制御の粒度 | glob パターンマッチ | 任意のスクリプトロジック |
| 実行タイミング | ツール呼び出し時 | 実行前・実行後・複数タイミング |
| ログ記録 | 不可 | 可 |
| 通知・副作用 | 不可 | 可 |
| 複雑な条件分岐 | 不可 | 可 |
フックの種別
Claude Code には以下のフックタイプが用意されています。
PreToolUse
ツールが実行される直前に呼び出されます。終了コードによって実行を許可・ブロックできます。
- 用途: 危険なコマンドのインターセプト、追加検証ロジック、実行前ログ
- 制御: 終了コード
0→ 許可、2→ ブロック(Claude にフィードバック)
PostToolUse
ツールが実行された直後に呼び出されます。実行結果を受け取って後処理できます。
- 用途: 実行ログの記録、通知送信、後続処理のトリガー
- 制御: 実行のブロックは不可(既に実行済みのため)
Notification
Claude Code がユーザーに通知を送るタイミングで呼び出されます。
- 用途: デスクトップ通知、Slack 通知、メール送信
Stop
Claude Code がセッションを終了するタイミングで呼び出されます。
- 用途: 終了時のクリーンアップ処理、セッションサマリーの保存
SubagentStop
サブエージェントが終了するタイミングで呼び出されます。
- 用途: サブエージェントの実行結果集約、ログ記録
PreCompact
/compact コマンドによりコンテキストが圧縮される直前に呼び出されます。
- 用途: 圧縮前のコンテキストのバックアップ
設定方法
settings.json への記述
Hooks は settings.json の hooks オブジェクトで設定します。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/pre-bash.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/post-edit.sh"
}
]
}
]
}
} matcher の書き方
matcher フィールドで対象ツールを指定します。
"matcher": "Bash" // Bash ツール全体
"matcher": "Read" // Read ツール全体
"matcher": "Edit" // Edit ツール全体
"matcher": ".*" // すべてのツール
"matcher": "Bash|Read" // Bash または Read フックスクリプトの基本構造
フックスクリプトは標準入力(stdin)から JSON 形式のコンテキスト情報を受け取ります。
#!/bin/bash
# stdin から JSON を読み込む
INPUT=$(cat)
# ツール名を取得
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
# 入力パラメータを取得
TOOL_INPUT=$(echo "$INPUT" | jq -r '.tool_input')
echo "Tool: $TOOL_NAME" >&2
echo "Input: $TOOL_INPUT" >&2
# 終了コード 0 = 許可
exit 0 stdin の JSON 構造(PreToolUse の例)
{
"session_id": "abc123",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf /tmp/old-files"
}
} 実践的な活用例
例 1: .env ファイルへのアクセスをブロック(Terminal レベル)
settings.json の deny ルールは Claude Code のツール呼び出しレベルでの制限です。PreToolUse フックを使えば、より深い Terminal レベルでインターセプトできます。
#!/bin/bash
# ~/.claude/hooks/block-env-access.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Bash で .env を cat しようとしている場合にブロック
if [ "$TOOL_NAME" = "Bash" ]; then
if echo "$COMMAND" | grep -qE '(cat|less|more|head|tail).*\.env'; then
echo '{"decision": "block", "reason": ".env ファイルの読み取りはブロックされています"}'
exit 2
fi
fi
# Read ツールで .env にアクセスしようとしている場合にブロック
if [ "$TOOL_NAME" = "Read" ]; then
if echo "$FILE_PATH" | grep -qE '\.env$|\.env\.'; then
echo '{"decision": "block", "reason": ".env ファイルへのアクセスはブロックされています"}'
exit 2
fi
fi
exit 0 settings.json での設定:
{
"hooks": {
"PreToolUse": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/block-env-access.sh"
}
]
}
]
}
} 例 2: ツール実行ログを記録する
#!/bin/bash
# ~/.claude/hooks/audit-log.sh
INPUT=$(cat)
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id')
# ログファイルに追記
echo "[$TIMESTAMP] Session: $SESSION_ID | Tool: $TOOL_NAME" >> ~/.claude/audit.log
exit 0 例 3: ファイル編集後に自動テストを実行
#!/bin/bash
# ~/.claude/hooks/post-edit-test.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# TypeScript ファイルが編集されたらタイプチェックを実行
if echo "$FILE_PATH" | grep -qE '\.ts$|\.tsx$'; then
npx tsc --noEmit 2>&1 | tail -5 >&2
fi
exit 0 例 4: Slack 通知
長時間タスクの完了時に Slack に通知する例です。
#!/bin/bash
# ~/.claude/hooks/notify-slack.sh
INPUT=$(cat)
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id')
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H 'Content-type: application/json' \
--data "{\"text\": \"Claude Code セッション完了: $SESSION_ID\"}" > /dev/null
exit 0 settings.json の Stop フックに設定:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/notify-slack.sh"
}
]
}
]
}
} フック実行環境と注意点
実行環境
Hooks のスクリプトは Claude Code と同じユーザー権限 で実行されます。つまり、Claude Code が書き込めるファイルにはフックスクリプトも書き込めます。逆に言えば、フックスクリプト自体が攻撃の対象になりうるため、以下の点に注意が必要です。
- フックスクリプトのパーミッションを
755に設定し、所有者のみ書き込み可能にする - フックスクリプトを Git 管理下に置く場合は、変更の差分を必ずレビューする
-
stdinから受け取った値を直接シェルで実行しない(インジェクション対策)
タイムアウト
フックスクリプトはデフォルトで 60 秒 のタイムアウトが設定されています。重い処理は非同期で行うか、バックグラウンドに逃がしましょう。
Remote Control モード
Claude Code を Remote Control モード(ヘッドレス実行)で使う場合、フックの実行環境が通常の対話セッションと異なります。CI/CD パイプラインに組み込む際は挙動を事前に確認することをおすすめします。
セキュリティ設計における Hooks の位置づけ
Claude Code のセキュリティ設計は、以下の多層防御として考えるとわかりやすいです。
| 層 | 手段 | 特徴 |
|---|---|---|
| 第 1 層 | settings.json の deny ルール | 設定が簡単・パターンマッチ |
| 第 2 層 | PreToolUse フック | より細かい条件でインターセプト |
| 第 3 層 | OS レベルのパーミッション | ファイルシステムの根本的な保護 |
| 第 4 層 | ネットワーク制御 | 外部通信の制限 |
settings.json の deny は「簡単・素早く設定できる第 1 防衛ライン」、Hooks は「より柔軟で細かい第 2 防衛ライン」と位置づけると良いと考えています。両者を組み合わせることで、より堅牢なセキュリティ設計が実現できます。
まとめ
Claude Code の Hooks は、パーミッション設定の限界を超えた柔軟な制御を可能にする強力な仕組みです。
- PreToolUse でツール実行前にインターセプト・ブロック
- PostToolUse で実行後のログ・通知・後処理
- Stop / SubagentStop でセッション終了時のクリーンアップ
最初は .env ファイルへのアクセスをブロックするシンプルなフックから始めて、徐々に自動化・通知・監査ログへと発展させていくのがおすすめです。
セキュリティや CI/CD との連携を強化したい方は、ぜひ Hooks の活用を検討してみてください。
関連記事もあわせてどうぞ:
- Claude Code のデータ取り扱いとセキュリティ設定を理解する
- .env のベストプラクティスと AI エージェント時代のシークレット管理

