お疲れ様です。みんみんです。
今回は Claude Code の Hooks について書きます。
正直、自分のなかで一番効果があった機能かもしれません。
目次
CLAUDE.md に書いたルール、守ってくれない問題
Claude Code を使っていると、こんなことが起きます。
- 勝手に
git commitして push する - 確認なしで subagent を大量に起動する
- 頼んでもいないファイルを新規作成する
- コードに長い説明コメントを書く
全部 CLAUDE.md に「やるな」と書いてあります。
でも守らない。毎回守らない。何度書いても守らない。
これは Claude が悪いというより、CLAUDE.md は「お願い」であって「強制」ではないということです。
LLM は確率的に動くので、ルールを100%守る保証がありません。
Hooks = 機械的な強制力
Hooks はシェルスクリプトです。
Claude Code のライフサイクルの特定のタイミングで必ず実行されます。
CLAUDE.md との違いを一言でいうと:
CLAUDE.md→ 「これやらないでね」(お願い。忘れることがある)Hooks→ 「これやったらブロックする」(強制。100%発火する)
設定は .claude/settings.json の hooks キーに書きます。
イベント(PreToolUse / PostToolUse / SessionStart 等)ごとにスクリプトを指定できます。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Agent",
"hooks": [
{
"type": "command",
"command": "/path/to/.claude/hooks/your-script.sh"
}
]
}
]
}
}
matcher でどのツールに反応するかを指定して、command で実行するスクリプトを指定します。
PreToolUse ならツール実行の前に走るので、条件に合えばブロックできます。
実際に使っている5つの Hook
全部、実際に事故が起きてから作ったものです。
予防じゃなくて対処。痛い目を見てから増えていきました。
1. subagent の無断起動をブロック
イベント:PreToolUse(matcher: Agent)
Claude Code は複雑なタスクを分割して subagent に投げることがあります。
便利ですが、確認なしで5〜6個同時に起動されると制御不能になります。
#!/bin/bash
echo '{"decision":"block","reason":"subagent を開く前に許可を取ること。"}'
シンプルですが効果は絶大。
無条件ブロック。ユーザーに許可を求めさせます。
2. git commit / push の無断実行を防止
イベント:PreToolUse(matcher: Bash)
CLAUDE.md に「commit/push は明確な指示があるまで禁止」と書いていましたが、普通に無視されました。
特に auto モードだと、作業が終わったら勝手にコミットして push まで行くことがあります。
#!/usr/bin/env bash
INPUT=$(cat)
CMD=$(jq -r '.tool_input.command // empty' <<<"$INPUT")
if echo "$CMD" | grep -qE '\bgit\b[^&|;]*\b(commit|push)\b'; then
jq -n --arg reason "commit/push は明確な確認が必要" \
'{"hookSpecificOutput":{"permissionDecision":"ask"}}'
else
exit 0
fi
Bash コマンドの中に git commit や git push が含まれていたら、"permissionDecision": "ask" で確認を挟みます。
block ではなく ask にしているのは、指示済みの commit まで止めたくないからです。
3. 新規ファイル作成の事前確認
イベント:PreToolUse(matcher: Write)
「ちょっとしたヘルパー関数」のつもりで勝手にファイルを作られることがあります。
既存ファイルの編集は OK、新規作成だけ確認を入れます。
#!/usr/bin/env bash
f=$(jq -r '.tool_input.file_path')
if [ -n "$f" ] && [ ! -e "$f" ]; then
echo '{"hookSpecificOutput":{"permissionDecision":"ask","permissionDecisionReason":"新規ファイル作成は事前確認が必要"}}'
fi
ファイルパスを取得して、ファイルが存在しなければ確認を挟む。
4行。これだけで不要なファイル増殖を防げます。
4. 説明コメントを書かせない
イベント:PostToolUse(matcher: Edit|Write)
Claude Code はコードを書くと、丁寧に説明コメントをつけてくれます。
「// ユーザー名を取得する」みたいなやつ。コードを読めばわかることを日本語で書かないでほしい。
Python スクリプトで、Edit / Write の後に新しく追加されたコメントを検査します。
判定ロジックはシンプルで、以下の3つに引っかかったら「説明コメント」と判定して警告を出します:
- 句点(。)が含まれている
- 「する」「した」「です」「ます」等の述語で終わっている
- 40文字以上ある
TODO や NOTE: や URL はホワイトリストで許可しています。
コメントは見出しだけ。句点なし、文にしない。これがルールです。
5. SessionStart で環境を自動整備
イベント:SessionStart
新しいセッションが始まるたびに実行されるイベントです。
環境チェックや初期設定の自動化に使えます。
自分の場合は、VSCode 拡張の特定の設定が更新のたびにリセットされる問題があり、
SessionStart で自動的にパッチを当てるスクリプトを走らせています。
他にも使い方はいろいろあります:
- 環境変数の読み込み確認
- 必要なツール(jq, gh 等)のインストールチェック
- 作業開始時のリマインドメッセージ表示
全部、事故から生まれた
正直に言うと、最初から Hooks を設計したわけじゃありません。
subagent のブロック → 確認なしで大量起動されて制御不能になったから。
commit/push のゲート → 作業が終わったら勝手にコミットされたから。
新規ファイルの確認 → 頼んでないファイルが増えていたから。
コメントの検査 → 毎回消す手間が発生していたから。
事故が起きるたびに Hook が1つ増える。Hook の数 = 過去の事故の数です。
Hooks の限界
万能ではありません。
Hooks が得意なのは「やってはいけないことを止める」です。
苦手なのは「やるべきことをやらなかった」を検知すること。
例えば「コミット前にレビュー結果を表示して確認ボタンを出す」というルールがあったとして、
Claude がそのステップを丸ごとスキップした場合、Hook では検知できません。
「実行された」ことは捕まえられるけど、「実行されなかった」ことは捕まえられない。
なので使い分けとしては:
- 禁止事項 →
Hooksで機械的にブロック - 手順・フロー →
Skillsで定義して従わせる - 方針・考え方 →
CLAUDE.mdに書く
3層で守る、というイメージです。
まとめ
AI に仕事を任せるなら、信頼するな、でも使え。
ルールは CLAUDE.md に、制約は Hooks に。
Hooks は Claude Code の中で唯一、LLM の判断を介さずに100%実行される仕組みです。
CLAUDE.md だけでは守れないことも、Hooks なら機械的に止められます。
自分の Hook は全部、事故から生まれました。
まだ事故が起きていない人は、先に入れておくと幸せになれるかもしれません。
参考になれば嬉しいです。
