Claude Code の hooks は、2025 年中盤に導入された仕組みで、エージェントのツール実行の前後や停止時に 任意のシェルコマンドを割り込ませる 機能です。
一言で言うと:
git の pre-commit hook のような仕組みを、AI エージェントのツール実行に対して設定できる
これにより、
- 危険なコマンド(
rm -rf、git push --force)を自動でブロック - 書き換えたファイルを自動でフォーマット
- ツール呼び出しのログを取る
- プロジェクト固有の品質ゲートをエージェントに守らせる
- セッション停止時に自動でテストを走らせる
といったことが、エージェントの挙動そのものを信じきらずに外側から規律化 できます。
本稿では、hooks の 4 種類・設定ファイルの書き方・代表的なユースケース・落とし穴を実例で整理します。
hooks の 4 種類
| hook | タイミング | ユースケース |
|---|---|---|
| PreToolUse | ツール実行の直前 | 禁止コマンドのブロック、承認要求 |
| PostToolUse | ツール実行の直後 | 自動フォーマット、ログ、再評価 |
| Stop | セッション停止時 | テスト実行、サマリー生成、通知 |
| UserPromptSubmit | ユーザが入力を送信した直後 | 入力のバリデーション、追記、置換 |
動作フロー
ユーザ入力
↓ UserPromptSubmit hook
Claude の応答生成
↓
ツール呼び出し決定
↓ PreToolUse hook (ブロック可能)
ツール実行
↓ PostToolUse hook
Claude の次の応答へ
↓
...(複数ターン)...
↓
セッション終了
↓ Stop hook
設定ファイルの場所と書式
settings.json の構造
Claude Code は複数の場所から設定を読み込みます:
~/.claude/settings.json— ユーザ全体.claude/settings.json— プロジェクト全体(commit 対象).claude/settings.local.json— プロジェクトローカル(commit しない)
hooks は hooks キーの下に書きます:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/path/to/pre-bash-hook.sh"
}
]
}
]
}
}
Matcher
matcher は正規表現で、どのツールにこの hook を適用するかを指定します。
"Bash"→ Bash tool にだけ"Edit|Write"→ Edit か Write""→ すべて"Bash\(git.*push.*\)"→git pushを含む Bash コマンドだけ
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 系の仕事を複数セル並列でやるときは:
.claude/settings.jsonの hooks でセキュリティ・フォーマット- MulmoTerminal の
script.jsonで定期タスク - Agent Skills で業務ロジック
を使い分けると、組織的な AI 利用がきれいに整理できます。
落とし穴
1. Hook の実行時間
Hook は同期的に実行されるので、遅い hook はエージェント全体を遅くします。
npm installを毎回走らせる → 遅すぎる- GitHub API を叩く → 遅すぎる
- ローカルのファイル書き込み → OK
原則: hook は 100ms 以内に完結させる。遅い処理は非同期(バックグラウンド)で起動して、hook 自体は即座に返す。
2. Hook のバグがエージェントを止める
Hook がクラッシュしたりエラーで無反応になると、Claude Code 全体が止まります。
- Hook は defensive に書く(
set -eだが、エラー時は空 JSON を返す) - 本番導入前に手動で動作確認
~/.claude/logs/のログで動作を追う
3. 権限と信頼
Hook はホスト上の任意のコマンドを実行できます。悪意ある hook スクリプトを .claude/settings.json 経由で導入されると、ホストが乗っ取られます。
- repo の
.claude/settings.jsonを信頼できない人から pull するときは中身を確認 - Hook スクリプトは実行権限を厳格に(
chmod 755、owner only) - CI 環境では hook を無効化するオプションも検討
4. 相互作用の難しさ
複数の hook が同じツールにマッチすると、順番や優先度が複雑になります。
- まずは 1 hook から始める
- 複数書くときは、matcher を絞って重複を避ける
- ログで実際にどの hook が走ったか確認
他の AI エージェント基盤での hooks
- Codex: 2025 年末から similar な hook 機構を導入
- Cursor: 独自の pre/post rule system
- MulmoTerminal: Claude Code の 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 つ減らす」を意識。
まとめ
- Claude Code の hooks は、ツール実行の前後やセッション停止時に任意のコマンドを割り込ませる仕組み
- 4 種類: PreToolUse / PostToolUse / Stop / UserPromptSubmit
.claude/settings.jsonのhooksキーに matcher + command で書く- 代表例: 危険コマンドブロック / 自動フォーマット / 監査ログ / 自動テスト / コンテキスト注入
- 落とし穴: 実行時間 / バグによる停止 / セキュリティ / 相互作用
- MulmoTerminal は hooks を全セルで継承、並列運用で特に効く
AI エージェントを信じきらず、外側で規律化する のが hooks の思想です。信頼より検証、を実装で担保する。
関連リンク
- Claude Code のベストプラクティス
- Claude Code vs Codex vs Gemini CLI
- Agent Skills とは — 自作スキルで Claude に専門性を注入する
- AI エージェントの evaluation (evals) 入門
- MulmoTerminal — Claude Code を並列実行するコックピット
Singularity Society はテクノロジー集団として MulmoClaude / MulmoTerminal / MulmoCast を開発しています。エンジニア・起業家向けの実践プログラム BootCamp も運営しています。

