コンテンツにスキップ

第5章 フック

「ファイルを編集したら毎回フォーマッタを実行してほしい」「特定のコマンドは絶対にブロックしたい」—— こうした 確実に毎回実行される自動処理 は、プロンプトや CLAUDE.md への記述では実現できません。
モデルは指示を「忘れる」可能性があるからです。

フック(Hooks) は、エージェントループの特定のタイミングでハーネスが 必ず 実行するシェルコマンドです。
モデルの判断を介さないため、決定論的に動作します。


イベント発火タイミング主な用途
PreToolUseツール実行の直前危険なコマンドのブロック、入力の検証
PostToolUseツール実行の直後フォーマッタ・Lint の自動実行
UserPromptSubmitユーザーがプロンプトを送信した時コンテキストの自動注入、入力チェック
NotificationClaude が許可待ち・入力待ちになった時デスクトップ通知・Slack 通知
StopClaude が応答を完了した時完了通知、後続処理のトリガー
SubagentStopサブエージェントが完了した時サブタスクの結果検証
PreCompactコンパクション(要約)の直前履歴のバックアップ
SessionStartセッション開始時環境情報の注入
SessionEndセッション終了時クリーンアップ、ログ記録
flowchart LR
    U["UserPromptSubmit"] --> Pre["PreToolUse"]
    Pre --> T["ツール実行"]
    T --> Post["PostToolUse"]
    Post --> Pre
    Post --> S["Stop"]

フックは settings.json の hooks セクションに定義します。
matcher でどのツールに反応するかを絞り込めます。

.claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "pnpm biome check --write \"$(jq -r '.tool_input.file_path' <<< \"$CLAUDE_HOOK_INPUT\")\" 2>/dev/null || true"
}
]
}
]
}
}

この例では、Edit / Write ツールでファイルが変更されるたびに Biome フォーマッタが自動実行されます。

フックコマンドには、イベントの詳細(ツール名・入力パラメータなど)が JSON として標準入力 から渡されます。jq で必要なフィールドを取り出すのが定番パターンです。


5.3 PreToolUse でのブロック — 終了コードによる制御

Section titled “5.3 PreToolUse でのブロック — 終了コードによる制御”

フックの 終了コード には意味があります。

終了コード意味
0続行を許可。
標準出力は(イベントにより)コンテキストに追加される
2ブロック
標準エラー出力がモデルにフィードバックされる
その他エラーとして扱われるが実行は続行

危険なコマンドを確実にブロックする例:

.claude/settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 ~/.claude/hooks/block-dangerous.py"
}
]
}
]
}
}
~/.claude/hooks/block-dangerous.py
import json, re, sys
data = json.load(sys.stdin)
command = data.get("tool_input", {}).get("command", "")
BLOCKED = [r"rm\s+-rf\s+/", r"git\s+push\s+--force\s+.*main"]
for pattern in BLOCKED:
if re.search(pattern, command):
print(f"ブロック: '{command}' は禁止パターンに一致します", file=sys.stderr)
sys.exit(2) # 終了コード2 = ブロックし、理由をモデルに伝える
sys.exit(0)

{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "pnpm test --silent --passWithNoTests" }
]
}
]
}
}

許可待ちになったらデスクトップ通知(macOS)

Section titled “許可待ちになったらデスクトップ通知(macOS)”
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude が入力を待っています\" with title \"Claude Code\"'"
}
]
}
]
}
}

全ツール実行をログに記録(監査用)

Section titled “全ツール実行をログに記録(監査用)”
{
"hooks": {
"PreToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -c '{time: now, tool: .tool_name, input: .tool_input}' >> ~/.claude/tool-audit.jsonl"
}
]
}
]
}
}

  • フックは無条件に実行される — モデルの判断を通らないため、フック自体のバグはすべてのセッションに影響します。
    まず手動でスクリプトをテストしてから登録しましょう
  • 実行時間に注意 — 重いフック(フルテストスイートなど)は毎回の編集を遅くします。
    対象を絞るか、軽量なチェックに留めます
  • 信頼できる設定のみ — フックは任意のシェルコマンドを実行します。
    他人のリポジトリの .claude/settings.json に悪意あるフックが含まれる可能性に注意してください(初回に確認プロンプトが表示されます)
  • 設定変更後は /hooks コマンドで現在有効なフックを確認できます

  • フックは、エージェントループの特定タイミングでハーネスが必ず実行する処理。
    「毎回確実に」はフックで実現する
  • PreToolUse(実行前の検証・ブロック)と PostToolUse(フォーマット・テスト)が二大用途
  • 終了コード 2 でツール実行をブロックし、理由をモデルにフィードバックできる
  • 強力な分、フック自体の品質とセキュリティには注意が必要