あなたはもう、エージェント向けの良い契約書の書き方を知っています。AGENTS.md に、どう働いてほしいかを伝えます。問題は、LLMがその契約書を読んで毎ターンあらためて判断し直すこと — だから重要なルールはほぼ毎回守られ、その「ほぼ」こそがあなたを噛むのです。hooks は次の一段です:ルールをモデルの頭から取り出してインフラに入れ、その判断に頼らず100%の確率で起きるようにする。引っかける先のライフサイクルのイベント、JSONの構造、各 hook がどこに存在しなぜ重要か、そして貼るだけで使える3つの本物の hook(自動フォーマット、危険なコマンドのブロック、デスクトップ通知)を Anthropic の公式ドキュメントから紹介します。最初の hook をセキュリティ付きで組むための唯一のマスタープロンプトも — hook はあなたの権限でシェルを走らせるからです。「契約書を書く」から「契約書が自分で実行されるようにする」への飛躍です。
AIを使うどのプロジェクトにも、モデルの善意を当てにするのをやめる瞬間が訪れます。AGENTS.md に、コードをフォーマットせよ、機密ファイルは触るな、テストを走らせよ、と書きました。そして90%はその通りにやってくれます。ですが残りの10%こそがあなたを噛むのです。本番の .env を編集してしまった回、フォーマットをすっ飛ばしてコミットが汚れた回、「一時的っぽい」という理由で間違ったフォルダに rm -rf を実行してしまった回です。
hooks の瞬間とは、こう考えたときです。「これがモデルの良い判断に依存しなかったら? ただ、いつでも、その判断に頼らず起きるとしたら?」。それこそが、Claude Code の公式ドキュメントが hooks のページの中心に据えている約束です。hooks はエージェントの振る舞いに対して 「決定論的な制御」 を与え、「LLM がそれを実行することを選ぶかどうかに頼るのではなく、特定のアクションが必ず起きることを保証する」(英語原文の忠実な訳)。この一文がこの資料全体のテーゼです。
その痛みは黙示録ではなく、浸食です。AIに何かを「いつも」やってと頼んでも、時々やってくれない。なぜならLLMは決定論的ではないからです。毎ターン、あらためて判断し直すのであり、コンテキストが詰まったターンでは、あなたのフォーマットのリマインダーが他の何千ものトークンの下に埋もれてしまうこともある。AIが反抗的なのではありません。確率的なシステムに一貫性を求めている のです。優秀だけれど注意散漫な人に、ガスの元栓を締めるのを一度も忘れないでとお願いするようなものです。ほとんどの夜は締めてくれる。だからこそあなたは油断してしまうのです。
.env、package-lock.json、.git/ の中身など。そしてここに、この資料を上級者向けたらしめている切り口があります。もしあなたが既にエージェント用の良い契約書(AGENTS.md)の書き方について読んだことがあるなら、hooks は 次のステップ です。「契約書を書く」(宣言的:何を望むかを伝える)から、「契約書が自分で実行されるようにする」(決定論的:機械が代わりに守る)へと進むのです。紙に書かれた法律と、角に立つ警官の違いです。
hook とは、Claude Code がそのライフサイクルの特定の時点で自動的に実行するシェルコマンドのことです。あなたは settings.json ファイルに一度だけ宣言します。それ以降、そのライフサイクルの時点が来るたびに、あなたのコマンドが走ります。モデルがその判断で発火させるのではありません。イベント が発火させるのです。そこに魔法があります。決定論的で、議論の余地がないのです。
公式ドキュメントには たくさんの ライフサイクルイベントが列挙されています。エージェントの作業のほぼどの瞬間にも対応するものがあります。数やリスト全体を暗記しないでください。考え方を身につけ、95%の時間で本当に使うものだけを覚えておきましょう。以下が、ドキュメントに載っている実際の名前そのままです。
rm -rf や保護ファイルへの編集を止める。compact の SessionStart)— コンテキストの圧縮の前後で、メモリが圧縮されるときに重要なものを失わないようにする。Pre に引っかける。すでに起きたことに 反応したい(フォーマット、通知、記録)なら Post に引っかける。すべての hook は、settings.json の "hooks" ブロックの中に存在します。構造は常に同じマトリョーシカです。イベント名 → matcher(何に適用するか)→ type: "command" と走らせる command を持つ hooks のリスト。一度見れば、もう忘れません。
{
"hooks": {
"PostToolUse": [ // 1. ライフサイクルの EVENTO(イベント)
{
"matcher": "Edit|Write", // 2. どのツールに適用するか
"hooks": [
{
"type": "command", // 3. シェルコマンドである
"command": "...tu comando..." // 4. 起きたときに何を走らせるか
}
]
}
]
}
}PreToolUse、PostToolUse)ではツール名でフィルタします。"Edit|Write" は「Edit または Write を使うときだけ」、"Bash" はシェルコマンドだけ、を意味します。空 の matcher("")は常にすべてに対して発火します。縦棒 | は選択肢を区切ります(最近のバージョンの Claude Code ではカンマも有効です:"Edit, Write" は等価)。hook を置く場所が、その適用範囲を定義します。これは肝心です。プロジェクトの hook はチームと共有されます(リポジトリにコミットされる)。グローバルな hook はあなただけのものです。公式の表が、それぞれどこに置くかをまとめています。
.claude/settings.json に置いて コミットする。そうすれば契約書は一人の頭の中に住むのをやめ、コードと一緒に旅するようになります。それが本当の力です。規律がリポジトリの一部になり、誰かが思い出さないといけない付箋ではなくなるのです。理論はもう十分。ここに、公式ドキュメントから取ってきた、貼るだけで使える3つの実際の hook があります。今日あなたが一番痛いものから始めてください。
定番です。Claude がファイルを編集または書き込むたびに、自動で Prettier をかけます。もう二度とフォーマットが不揃いなコミットはありません。プロジェクトの .claude/settings.json に置きます。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}jq -r '.tool_input.file_path' はその JSON から 編集されたファイルのパスを抽出 し、xargs npx prettier --write がそれを Prettier に渡します。jq はコマンドライン用のJSONリーダーです。macOS なら brew install jq、Debian/Ubuntu なら apt-get install jq でインストールしてください。これが恐怖を取り除いてくれるものです。各 Bash コマンドを実行 前 にチェックし、破壊的なものが含まれていれば 拒否する PreToolUse の hook です。ここではドキュメントが明快に述べている技術的な細部が本当に重要です。終了コード2で終了するとブロックされ、標準エラー出力(stderr)に書いたものが Claude に説明として届き、修正のヒントになります。まずスクリプト。
#!/bin/bash # .claude/hooks/block-rm-rf.sh INPUT=$(cat) COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command') if echo "$COMMAND" | grep -q "rm -rf"; then echo "ブロックされました: 'rm -rf' は許可されていません。再帰・強制ではなく、具体的なパスを削除してください。" >&2 exit 2 # exit 2 = アクションをブロック; stderr がフィードバックとして Claude に届く fi exit 0 # exit 0 = 異議なし; 通常の権限フローが続く
実行可能にして、スクリプトを指すように settings に登録します。
chmod +x .claude/hooks/block-rm-rf.sh
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-rm-rf.sh"
}
]
}
]
}
}grep -q "rm -rf" は明白なケースは捕まえますが、rm -fr、変な空白の入った rm -rf、rm --recursive --force はすり抜けます。目に見える安全網、そしてAIへの教育的フィードバックとしては役立ちますが、防弾装備と混同してはいけません。ドキュメント自身が遠回しなく述べています。hook のフィルタは best-effort(ベストエフォート)であり「フェイルオープン」する(コマンドをパースできなければ通してしまう)。だから、誰も回避できない ハードな禁止 には、hook ではなく 権限システム(permissions.deny)を使ってください。正しいパターンはこうです:反応して知らせるための hook、本物の錠前のための permission rules。PreToolUse は、`bypassPermissions` でも `--dangerously-skip-permissions` でも、ツールを拒否します。つまり、あなた(またはAI)が権限の壁をすべて下げていても、あなたのブロック用 hook は立ったままなのです。このルールは非対称であり、意図的にそう設計されています。hooks はポリシーを 強化 することはできても、権限ルールが許す範囲を超えて緩めることは決してできません。ブロック用 hook は、あなた自身ですら誤って回避できないルールなのです。ターミナルを見張るのをやめるためのものです。Claude が終わる、または許可を必要とするとき、デスクトップ通知が飛んで、あなたは別のことをしに行けます。グローバルな ~/.claude/settings.json に置きます(osascript を使った macOS の例)。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code があなたの注意を必要としています\" with title \"Claude Code\"'"
}
]
}
]
}
}notify-send 'Claude Code' 'Claude Code があなたの注意を必要としています' を使い、Windows(PowerShell) では System.Windows.Forms の MessageBox を使います。JSONの構造は同じです — 変わるのは command の行だけ。ガイド自身が書いている macOS の小技:通知が出ない場合は、一度 osascript -e 'display notification "test"' を走らせ、その後システム設定 → 通知 で Script Editor に権限を与えてください。hooks は何にでも使うものではありません。頭の中のルールはシンプルです。何かが 常に、機械的に、判断なしで起きるべき なら、それは hook です。何かが ケースごとの判断を要する なら、決定論的な hook で無理に縛らないでください。モデルに判断させる(あるいは、ドキュメントがサポートしている prompt/エージェント型の hook を使う。ただしそれは別次元の話です)。
.env を触る、再帰削除、.git/ への書き込み):それはブロック用の PreToolUse — ハードな錠前としては権限ルールで裏打ちする。PostToolUse。PostToolUse に注意:すでに起きたことは取り消せません — 反応するだけです。阻止する には常に PreToolUse。複雑なロジックを詰め込みすぎると hook はもろくなります。短く、単一目的に保ってください。ここで実践的な細部です。ドキュメント自身が、hook を説明して Claude に書かせることを勧めています。ですが、うまく — そして安全に — いくには、「hook を入れて」ではなく、構造化された依頼を与えるのがよいでしょう。これがこの資料の唯一のマスタープロンプトです。ひとつだけ、強力で、安全ブレーキ付きであなたの最初の hook を設計します。
自分のワークフローのルールを自動化するために、Claude Code の最初の hook を組みたいです。私が常に保証したいルールはこれです:[ルールを記述する。例:「編集したファイルを毎回 prettier でフォーマットする」/「ファイルを再帰的に削除するコマンドをブロックする」/「.env や .git/ の中身が編集されるのを阻止する」/「終わったら通知で知らせる」]。 何かを書き始める前に、これを分かりやすい言葉で答えて、うまく設計するのを手伝ってください(私はプログラミングをしません): 1. このルールに正しいライフサイクルの EVENTO(イベント)。ルールが何かを阻止するものなら、PreToolUse であるべき(前に起き、ブロックできる)。すでに行われたことに反応する(フォーマット、通知、記録)なら、PostToolUse か Notification であるべき。どれを選び、なぜかを教えてください。 2. 正確な MATCHER(どのツールに適用するか:Edit|Write、Bash、または全部なら空)と、なぜ他ではなくそれかの理由。できるだけ狭く保ってください:matcher が広すぎると、hook が本来ではない場所で発火します。 3. settings.json が存在すべき場所: - このリポジトリのチーム全員が守るべきルールなら → .claude/settings.json(コミットされる)。 - 私のマシンとすべてのプロジェクト用だけなら → ~/.claude/settings.json。 - ローカルでプライベートなら → .claude/settings.local.json。 どれか、そしてなぜかを教えてください。 4. 貼るだけで使える、完成した JSON ブロック。hook を組んだ状態で。別スクリプトが必要なら(PreToolUse でのブロックでは典型的)、完全な .sh スクリプトも渡し、chmod +x で実行可能にするのを私に思い出させてください。 5. ブロック用の hook の場合:exit 2 と、なぜブロックされたかを説明する明確な stderr メッセージを使い、あなた自身(Claude)がその理由を受け取って修正できるようにしてください。無言にしないこと。そして、このルールがハードな錠前として権限ルール(permissions.deny)も必要かどうかを私に知らせてください。hook の中の grep は best-effort であり回避されうるからです。 6. セキュリティ、必須:この hook がどんなシェルコマンドを走らせるのかを一文で説明し、破壊的なことは何もせず、どこにもデータを送らないことを私に確認してください。hook はあなたの権限でシェルを走らせること、そして私が理解しているコマンドだけを保存すべきことを私に思い出させてください。 7. どうテストするか:hook が登録されていることを確認する方法(Claude Code 内の /hooks コマンド)と、本物を壊さずに実際に発火することをテストする方法を教えてください。 まず設計だけ(イベント、matcher、場所)を見せて、次に JSON と必要ならスクリプト、最後にセキュリティの説明とテストを見せてください。私の settings.json はまだ変更しないでください:自分で貼る前にブロックを見直したいのです。
このパターンに注目してください。まず設計し、セキュリティを見直し、そしてあなた自身がブロックを貼る。hook を理解せずに設定に紛れ込ませることは決してありません。あらゆる強力な自動化を守る、同じ2段階の規律です。機械が提案し、あなたが承認する。
こんがらがらないように、チャットでAIに任せられることと、あなたの仕事のままであることを整理します。
.sh スクリプトを、jq、exit 2、stderr メッセージ付きで生成する。settings.json に置くべきかを説明する。chmod +x、足りなければ brew install jq。settings.json に。安全網が見直していないコードであってはならない。PreToolUse、反応には PostToolUse/Notification。PreToolUse のように、常に起きるのです。それは hook と同じ哲学を、ターミナル1台ではなくチーム全体に適用したものです。品質が誰かの記憶頼みの約束ではなく、回避できないベルト上のセンサーになる。あなたはルールを一度置く。システムが永遠にそれを守るのです。Join 4,200+ builders. No credit card. Build your first app with AI in minutes.