Claude Code の hooks 完全ガイド — PreToolUse / PostToolUse でエージェントを規律化する

Claude Code の hooks 完全ガイド — PreToolUse / PostToolUse でエージェントを規律化する

Claude Code の hooks は、2025 年中盤に導入された仕組みで、エージェントのツール実行の前後や停止時に 任意のシェルコマンドを割り込ませる 機能です。

一言で言うと:

git の pre-commit hook のような仕組みを、AI エージェントのツール実行に対して設定できる

これにより、

といったことが、エージェントの挙動そのものを信じきらずに外側から規律化 できます。

本稿では、hooks の 4 種類・設定ファイルの書き方・代表的なユースケース・落とし穴を実例で整理します。

hooks の 4 種類

hook タイミング ユースケース
PreToolUse ツール実行の直前 禁止コマンドのブロック、承認要求
PostToolUse ツール実行の直後 自動フォーマット、ログ、再評価
Stop セッション停止時 テスト実行、サマリー生成、通知
UserPromptSubmit ユーザが入力を送信した直後 入力のバリデーション、追記、置換

動作フロー

ユーザ入力
   ↓ UserPromptSubmit hook
Claude の応答生成
   ↓
ツール呼び出し決定
   ↓ PreToolUse hook (ブロック可能)
ツール実行
   ↓ PostToolUse hook
Claude の次の応答へ
   ↓
...(複数ターン)...
   ↓
セッション終了
   ↓ Stop hook

設定ファイルの場所と書式

settings.json の構造

Claude Code は複数の場所から設定を読み込みます:

hooks は hooks キーの下に書きます:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/pre-bash-hook.sh"
          }
        ]
      }
    ]
  }
}

Matcher

matcher は正規表現で、どのツールにこの hook を適用するかを指定します。

matcher の設計次第で、hook の実行コストと柔軟性が決まります。

Hook の実装

Hook はシェルコマンドです。実行時に標準入力から JSON が渡され、標準出力で結果を返します:

入力(stdin):

{
  "tool_name": "Bash",
  "tool_input": {
    "command": "git push origin main --force"
  }
}

出力(stdout):

{
  "decision": "block",
  "reason": "git push --force to main is forbidden"
}

decision: "block" を返すと、Claude Code はそのツール呼び出しを拒否して Claude に理由を伝えます。

代表的なユースケース

1. 危険コマンドのブロック

.claude/hooks/block-dangerous.sh:

#!/usr/bin/env bash
# PreToolUse hook: 危険なコマンドをブロック
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // ""')

# Deny list
if echo "$command" | grep -qE "rm -rf (/| ~)|git push.*--force.*main|DROP TABLE"; then
  jq -n --arg c "$command" '{
    decision: "block",
    reason: ("Dangerous command blocked: " + $c)
  }'
  exit 0
fi

# 許可
jq -n '{}'

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [{ "type": "command", "command": ".claude/hooks/block-dangerous.sh" }] }
    ]
  }
}

これで、エージェントが暴走しても最低限の破壊的操作は防げます。

2. 自動フォーマット

Edit や Write の直後に自動フォーマッタを走らせる。

#!/usr/bin/env bash
# PostToolUse hook: TypeScript ファイルを prettier にかける
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path // ""')

if [[ "$file_path" == *.ts || "$file_path" == *.tsx ]]; then
  npx prettier --write "$file_path" > /dev/null 2>&1
fi

jq -n '{}'

エージェントがコードを書いた瞬間に prettier が走るので、スタイル違反が溜まりません。

3. ツール呼び出しの監査ログ

.claude/hooks/audit-log.sh:

#!/usr/bin/env bash
input=$(cat)
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$timestamp $input" >> ~/.claude/audit.log
jq -n '{}'

全ツール呼び出しが ~/.claude/audit.log に残ります。後からセッションの挙動を再構築できる。

4. Stop hook でテスト実行

セッションが終わったら自動でテストを走らせる:

#!/usr/bin/env bash
# Stop hook: セッション終了時に軽量テストを実行し、落ちていたら通知
cd /path/to/project
if ! yarn test:fast > /tmp/test-result.log 2>&1; then
  osascript -e 'display notification "Tests failed after Claude session" with title "Claude Code"'
fi
jq -n '{}'

5. UserPromptSubmit でコンテキスト注入

ユーザが入力したプロンプトに自動で情報を付加する:

#!/usr/bin/env bash
# UserPromptSubmit hook: 「今の時刻は X です」を全プロンプトに追加
input=$(cat)
prompt=$(echo "$input" | jq -r '.prompt')
current_time=$(date "+%Y-%m-%d %H:%M:%S %Z")
new_prompt="$prompt\n\n(現在時刻: $current_time)"
jq -n --arg p "$new_prompt" '{prompt: $p}'

このパターンは、プロジェクト固有の文脈(git ブランチ名、環境変数、現在時刻)をエージェントに常に知らせる用途で効きます。

MulmoTerminal との統合

MulmoTerminal は Claude Code の設定をそのまま継承するので、.claude/settings.json に書いた hooks は MulmoTerminal で動くすべてのセルで有効になります。

9 セル並列で動かしていても、危険コマンドブロックが全セルで共通して効く。これがマルチセッション運用で非常に効きます。

MulmoTerminal 固有の統合

MulmoTerminal には hooks を補完する カスタムスキル や スクリプト実行 の仕組みもあります。feature-request 系の仕事を複数セル並列でやるときは:

を使い分けると、組織的な AI 利用がきれいに整理できます。

落とし穴

1. Hook の実行時間

Hook は同期的に実行されるので、遅い hook はエージェント全体を遅くします。

原則: hook は 100ms 以内に完結させる。遅い処理は非同期(バックグラウンド)で起動して、hook 自体は即座に返す。

2. Hook のバグがエージェントを止める

Hook がクラッシュしたりエラーで無反応になると、Claude Code 全体が止まります。

3. 権限と信頼

Hook はホスト上の任意のコマンドを実行できます。悪意ある hook スクリプトを .claude/settings.json 経由で導入されると、ホストが乗っ取られます。

4. 相互作用の難しさ

複数の hook が同じツールにマッチすると、順番や優先度が複雑になります。

他の AI エージェント基盤での hooks

標準化は進んでいませんが、「エージェントの外側で規律化する」設計思想は共通です。

自分で hooks を書き始める最小ステップ

Step 1: 1 つの用途から始める

まず危険コマンドのブロックか、自動フォーマット の片方だけ書く。両方同時に始めると、どちらが問題か切り分けづらい。

Step 2: .claude/settings.local.json でテスト

commit 対象の .claude/settings.json ではなく、まず .claude/settings.local.json に書いて自分だけで試す。1 週間動かして、問題が出ないか確認。

Step 3: チームに広げる

安定したら .claude/settings.json に移して commit。チーム全員が同じ hooks を使う。

Step 4: ログで観察

~/.claude/logs/ と自作の audit.log を定期的に見る。「予期しないブロック」「意図しない hook 発動」を探す。

Step 5: 追加

必要になったら追加の hook を書く。常に「shouldn’t be here なら 1 つ減らす」を意識。

まとめ

AI エージェントを信じきらず、外側で規律化する のが hooks の思想です。信頼より検証、を実装で担保する。

関連リンク


Singularity Society はテクノロジー集団として MulmoClaude / MulmoTerminal / MulmoCast を開発しています。エンジニア・起業家向けの実践プログラム BootCamp も運営しています。

この記事をシェア

関連記事

記事一覧に戻る