A
AIエージェントの仕組み
ch8-s4 · Hooks

Hooks で動作を強制制御

約 14 分

08-04. Hooks で Claude の動作を制御する

この回のゴール

1. 動機: Skills では「強制」できない

08-03 で作った Skills は Claude が「使うべき」と判断したら呼ばれる = lazy。 だが業務には 絶対に毎回守らせたい ルールがある:

Hooks = Claude のセッション中、特定のイベントで 無条件に実行されるシェルコマンド

2. Hook の主要イベント

Event 発火タイミング 主な用途
PreToolUse Claude が tool (Edit/Bash 等) を呼ぶ直前 危険コマンドのブロック、入力検査
PostToolUse tool 実行直後 フォーマッタ、テスト、commit 自動化
Stop Claude のターンが終わる時 セッションログ保存、通知
UserPromptSubmit ユーザーがプロンプト送信時 コンテキスト自動注入
SessionStart セッション開始時 環境変数 export、状態確認

3. Exit Code = 強制力

Hook はシェルコマンド(or スクリプト)。返り値が:

Exit Code 意味 Claude の動作
0 成功 そのまま続行
2 ブロック tool 実行を中止、Hook の stderr を Claude に伝える
その他 (1, 137 など) 警告 続行はするが Claude に通知

exit 2唯一の強制ブロック手段

4. 設定ファイル .claude/settings.json

最小例(危険コマンドブロック + Edit 後フォーマッタ):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -qE 'rm -rf|sudo rm'; then echo 'Blocked: dangerous command' >&2; exit 2; fi"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "ruff format $CLAUDE_FILE_PATHS 2>&1 || true"
          }
        ]
      }
    ]
  }
}

環境変数(Hook に渡されるもの)

5. ハンズオン

5.1 危険コマンドブロック Hook

上記の例の PreToolUse だけをまず入れて起動:

claude
> ホームディレクトリ全部消して

→ Claude が rm -rf ~/ を試みる → Hook が exit 2 → ブロックされる挙動を確認。

5.2 Edit 後フォーマッタ Hook

Python リポジトリで ruff (or black, prettier) をインストール。

> README.md を整形して(行末スペース削除など)

→ Edit 後に ruff format が走り、フォーマット済みになることを確認。

5.3 Stop Hook でログ保存

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"[$(date)] session $CLAUDE_SESSION_ID ended\" >> ~/.claude/sessions.log"
          }
        ]
      }
    ]
  }
}

セッション終了ごとに ~/.claude/sessions.log に追記される。

6. アンチパターン

症状 原因 対策
セッションが遅い Hook が長時間ブロッキング (重いテストを毎回実行) Hook 内で軽量チェックのみ、重い処理はバックグラウンド
Hook で誤ってブロック 正規表現が広すぎる grep -qE のパターンを慎重に、テストする
Hook 実行で command not found パス設定が PATH に通っていない コマンドはフルパスで書く
デバッグが難しい Hook の出力が見えない claude --debug で Hook の stderr 確認

7. CLAUDE.md / Skills / Hooks の総まとめ

強制力 場面
CLAUDE.md なし(参考情報) 常時 プロジェクトの全体像、コーディング規約
Skills なし(Claude が判断) 場面別 コミット規約、PR レビュー観点
Hooks 強制(exit 2 でブロック可) イベント別 フォーマッタ、危険コマンド阻止、ログ

→ 階層: CLAUDE.md (Soft) → Skills (Lazy) → Hooks (Hard)

8. 今回の限界 (notes に書く内容)

参考

📝 理解度クイズ (3 問) 💡 ログインすると進捗が保存されます

💬 このサブステップの Q&A

まだ質問はありません。最初の質問を投稿してみましょう。

質問の投稿にはログインが必要です。