Claude Code hooksの設定は1つから。毎回の指示を自動実行に変える書き方と、動かないときの直し方
CLAUDE.mdに書いたのに守られないルールは、守るかどうかがAIの判断に委ねられています。C…

hooksの解説でよく見かけるのは、イベントの一覧表と、ファイルを保存した直後にフォーマッタを走らせるサンプルです。ただ、私が知りたかったのは一覧表のほうではありませんでした。私の作業フォルダにはCLAUDE.mdという指示書が30ファイル置いてあって、「消す前に必ず確認する」「集計用のデータ基盤には読み取り以外を行わない」といったルールが書いてあります。それでも、ときどき破られます。CLAUDE.mdはお願いで、hooksは強制という違いが、そのまま守られるかどうかの差になっていました。settings.jsonの書き方、置き場所、動かないときの確認、そして入れすぎたときの減らし方まで、実際に手元で回している側から順に書いていきます。仕様の動きが速い分野なので、イベント名などは2026年8月時点のものとして読んでください。
Claude Code hooksとは何か
hooksは、日本語の記事では「フック」と書かれることもあります。名前のとおり、Claude Codeの動きのどこかに、自分の処理を引っかけておく仕組みです。
引っかける中身はシェルコマンドです。シェルコマンドというのは、黒い画面(ターミナル)に打ち込む1行の命令のことで、「このファイルを整えて保存し直す」「メッセージを送る」「音を鳴らす」といった作業を1行で書けます。hooksでやるのは、そのコマンドを「いつ走らせるか」だけ決めて登録しておく作業です。
肝心なのは、Claudeが「走らせたほうがいいかな」と判断する余地が無い点です。登録したタイミングが来たら、必ず走ります。忙しいから今回は省く、という挙動が起こりません。頼み忘れても走りますし、Claudeの機嫌にも左右されません。
Claude Code自体をまだ触っていない方は、先にClaude Codeの始め方と、できることの全体像を読んでからのほうが分かりやすいと思います。hooksは、日常的に使っていて「毎回同じ指示をしているな」と気づいたあとに手を出すもので、初日に必要になるものではありません。
CLAUDE.mdに書いたのに破られたルール
hooksに手を出した理由は、はっきりしています。指示書に書いたのに守られないルールが、いくつかあったからです。
私のCLAUDE.mdには、削除についてこう書いてあります。消したいものが出てきたら、その日の日付を付けたフォルダへ移動するだけにして、削除そのものは必ず私に確認してから行う。ところが、しばらく運用していると「.DS_Storeだけなので消しました」「空のフォルダだけなので整理しました」という報告が返ってきます。悪意はありません。判断としてはむしろ親切です。ただ、私が決めたのは「例外なく聞く」だったので、そこが判断で埋められた時点でルールとしては機能していません。
仕事で使っている集計用のデータ基盤についても、読み取り以外はしない、と何度も書いています。書き込みや構造の変更は影響範囲が読めないので、原則として触らせません。文章で書ける以上のことは、文章では担保できないという話です。指示書に書いたルールは、守るかどうかがモデル側の判断に委ねられます。ほとんどのルールはそれで回っていて、抜けられると困るものだけが、私の場合は削除と集計用データへの書き込みでした。
hooksへ移すべきなのは、破られたときに実害が出るルールだけです。全部を移す必要はありませんし、移せるものでもありません。
CLAUDE.mdとhooksの使い分け
両者は代わりになりません。CLAUDE.mdは方針や判断基準を伝えるためのもので、hooksは決まった手順を機械的に走らせるためのものです。読み手が違う、と言ってもいいかもしれません。
| CLAUDE.md | hooks | |
|---|---|---|
| 性質 | お願い(読んで従う) | 強制(必ず走る) |
| 守られ方 | ときどき抜ける | 抜けない |
| 書ける中身 | 方針・判断基準・言葉づかい | 決まった処理の実行と停止 |
| 直すとき | 文章を足すだけ | JSONとコマンドを書く |
| 向いている用途 | 間違えてもやり直せること | 間違えると取り返しがつかないこと |
私はCLAUDE.mdを30ファイル置いていますが、階層で役割を分けています。いちばん上には、私自身の情報と、どこに何を置くかという全体のルールを書いています。ひとつ下の領域ごとのフォルダには、その領域だけで通じる約束事を置きます。さらに個別の案件フォルダには、その案件でしか使わない決まりごとを置きます。近いフォルダで作業しているときほど細かいルールが読まれる作りにしてあって、いちばん上の1枚が長くなりすぎるのを防いでいます。
階層を分けても、届かないものは残ります。文章量が増えるほど、後半のルールは薄まっていくからです。だから「絶対に外せない数本」だけをhooksへ下ろす、という順番になりました。指示書を分厚くすることと、hooksを増やすことは、別の作業として考えたほうが上手くいきます。前者を厚くしても、後者の代わりにはなりません。
hooksのイベントと発火するタイミング
hooksは「イベント」という単位でタイミングが決まっています。イベント名を全部覚える必要はありません。私が実際に中身を入れているのは、いまのところ1つだけです。ただ、どこに引っかけられるのかを一度眺めておくと、自分の困りごとがどれに当たるか見当が付きます。
| イベント | 走るタイミング | よくある用途 |
|---|---|---|
| PreToolUse | ツールを使う直前 | 危ないコマンドを実行前に止める |
| PostToolUse | ツールを使った直後 | 整形・検査・記録 |
| UserPromptSubmit | こちらが指示を送った直後 | 共通の前置きを足す |
| Notification | Claudeが許可を求めてきたとき | 通知音・デスクトップ通知 |
| Stop | 応答が終わったとき | 終了の知らせ、仕上げの検査 |
| SubagentStop | サブエージェントが終わったとき | 並列で走らせた作業の締め |
| SessionStart / SessionEnd | セッションの開始・終了 | 前提の読み込み、記録の保存 |
| PreCompact | 会話が圧縮される直前 | 消える前に書き出す |
ひとつ、読むときに注意が要ります。イベントの数は解説記事によってばらつきがあり、14個と書いてあるもの、23個、26個、30個と書いてあるものが同時に検索結果に並びます。追加された時期が違うだけで、どれかが嘘というわけではありません。ただ、実際に書くときは公式ドキュメントの一覧を開いて、いま使えるイベント名を確かめたほうが早いです。うろ覚えで書いた名前は、間違っていても警告が出ず、静かに無視されます。
最初のうちは、次の対応だけ頭に入れておけば大丈夫です。PostToolUseは「何かした直後」に走り、Stopは「応答が終わったとき」に走ります。前者はファイルを触ったあとの後始末に、後者は一区切りついたことを知らせるのに向いています。覚えるのは2つだけ。毎回口で言っている注意の大半は、どちらかに移せます。
settings.jsonの置き場所と3つのスコープ
hooksはsettings.jsonというファイルに書きます。JSONというのは、設定を書くための決まった形式のテキストで、波かっこと引用符で項目を並べていくものです。プログラムというより、住所録に近い書式だと思ってください。
置き場所は3つあって、届く範囲がそれぞれ違います。
~/.claude/settings.json 自分の全プロジェクトに適用される <プロジェクト>/.claude/settings.json そのプロジェクトだけ。共有される <プロジェクト>/.claude/settings.local.json そのプロジェクトの、自分だけの設定
いちばん上は、パソコン全体の設定です。どのフォルダで作業していても読み込まれます。真ん中はプロジェクトの中に置くもので、バージョン管理に含めればチームの全員に配られます。いちばん下のlocalが付くほうは共有されない置き場で、自分の手元でだけ試したいものを入れます。
3つは打ち消し合うのではなく、重なって動きます。同じイベントに別々のファイルからhookが登録されていれば、両方とも走ります。1つだけ動くと思い込んでいると、覚えのない処理が挟まって混乱しますし、逆に「上書きしたつもりが消えていない」ということも起きます。設定を減らしたいときは、書き換えるファイルを間違えていないか先に確かめたほうが早いです。/hooksで一覧を出せば、いま何が読み込まれているかがまとめて見えます。
私はhooksをプロジェクト側のsettings.jsonに置いています。作業内容がフォルダごとに違うので、全プロジェクト共通にすると、関係ないところで走って邪魔になるからです。逆に、パソコン全体で守りたいこと、たとえば「特定のフォルダには絶対に書き込ませない」といった防御は、いちばん上の階層に置いたほうが漏れません。会社のパソコンでは、管理者が配る設定が別に用意されていることもあるので、思ったとおりに動かないときは自分の書いたファイルだけを疑わないほうがいいでしょう。
hooksの設定の書き方
書式は3階層のネストになっています。イベント → matcher(どのツールを対象にするか)→ 実際に走らせるコマンドの配列という順番です。最初は入れ子が深く見えますが、意味が分かれば単純です。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/format.sh"
}
]
}
]
}
}
読み下すと、「ファイルを書いたり編集したりした直後に、format.shというファイルを実行する」となります。matcherに書いたWrite|Editは、WriteかEditのどちらかのツールが使われたとき、という指定です。縦棒はor(または)を表す記号で、正規表現という書き方の一部です。空欄にすればすべてのツールが対象になりますし、Bashだけに絞ることも、MCP経由の道具をmcp__サーバー名__ツール名の形で名指しすることもできます。
matcherの絞り方は、やりたいことから逆算すると迷いません。書き上がったファイルに何かしたいならWrite|Edit、コマンドの実行を見張りたいならBash、外部サービスへつなぐ道具だけを止めたいならMCPのツール名です。逆に、まず全部の動きを眺めたい段階なら、空欄にして記録だけ取るのも手です。広げすぎると関係ないツールのたびに走って待ち時間が増えますし、狭くしすぎると狙った場面で走ってくれません。最初は狭めに書いて、取りこぼしに気づいたら足す順番が安全です。なお、Stopのように対象ツールという概念がないイベントでは、matcher自体を書きません。
コマンドの中身は、直接1行で書いても構いませんし、別ファイルのシェルスクリプトを呼ぶ形にしてもかまいません。シェルスクリプトというのは、さきほどのコマンドを何行かまとめて1つのファイルにしたもので、拡張子は.shを付けるのが一般的です。少し複雑なことをするなら、後者が楽です。JSONの中に長いコマンドを書くと、引用符のエスケープで読めなくなります。$CLAUDE_PROJECT_DIRはClaude Codeが用意している変数で、プロジェクトのフォルダの場所が入ります。相対パスで書くと動かないことが多いので、ここを使うか、絶対パスで書きます。
もうひとつ大事なのが、hookに渡ってくる情報の受け取り方です。「どのファイルを触ったのか」といった中身は、標準入力からJSONで渡ってきます。シェルの変数に自動で入るわけではないので、jqのようなコマンドで取り出す必要があります。最初のつまずきどころで、変数から取るつもりで書くと、エラーも出さないまま何も起きません。動かないときは、まず受け取り方を疑うのがおすすめです。
終了コードとJSON出力でできる制御
hookは走るだけではなく、Claudeの動きに口を挟めます。手段は2つあって、簡単なほうが終了コードです。
終了コードというのは、コマンドが終わるときに返す数字のことです。0なら成功、それ以外なら失敗、というのが一般的な約束になっています。Claude Codeでは、この数字の意味が決められています。
| 終了コード | 起きること |
|---|---|
| 0 | そのまま進む。出力は記録に残る |
| 2 | 止まる。エラー出力の文章がClaudeに返り、Claudeが読む |
| その他 | 警告は出るが、処理は続く |
2が返せる意味は大きいです。PreToolUseで2を返せば、そのツールは実行される前に止まります。しかも、なぜ止めたのかをエラー出力に書いておけば、その文章がClaudeに渡ります。「このフォルダは消さずに移動してください」と書いておけば、Claudeは止められた理由を読んで、移動のほうをやり直します。冒頭に書いた削除のルールは、まさにここで機械的に止められる種類のものです。
もっと細かく指定したいときは、標準出力にJSONを返す方法があります。許可するのか、止めるのか、理由は何か、といった項目を明示できるもので、決定制御(decision control)と呼ばれます。ただ、書式が細かく、更新も入るので、必要になってから公式ドキュメントで確かめるほうが確実です。個人で使う範囲なら、終了コードだけで済むことがほとんどでしょう。
最初に入れる1つ、次の3つ、入れなくていいもの
解説記事はレシピを10個並べてくれますが、優先順位までは書いてありません。全部を一気に入れると、どれが原因で止まったのか分からなくなります。
私が最初に入れたのは、ファイルを書き換えた直後に体裁を整えるだけのhookでした。PostToolUseにWrite・Editでマッチさせて、対象のファイルの種類も絞ってあります。体裁を整えるというのは、字下げや空白の入れ方を決まった形に揃えて保存し直す作業のことで、人がやっても機械がやっても結果が同じになる種類の仕事です。失敗しても作業は止まりませんし、走ったかどうかがファイルの見た目ですぐ分かります。1つ入れて、実際に発火するのを目で確かめてから次に進むのが、遠回りのようで速いです。
次に足すなら、この3つが順当だと思います。1つ目は終わったことを知らせる通知です。Stopに音を鳴らすコマンドを引っかけるだけで、長い作業のあいだ席を外せるようになります。2つ目は危ないコマンドの停止です。PreToolUseでBashを対象にして、削除や公開に当たる語が含まれていたら終了コード2で止めます。3つ目は作業の記録です。いつ何のファイルを触ったかを1行ずつ書き足しておくと、あとで追いかけられます。
逆に、私が入れなくてよかったと思っているものもあります。すべてのツールにマッチさせる詳しい監査ログは、個人の作業ではまず読み返しません。テストが通るまでStopで終わらせない、という品質ゲートも、開発チームなら価値がありますが、書きものが中心の使い方では止まるだけで進みませんでした。Stopで終わらせない作りは、条件を満たすまで止めては再開を繰り返すので、うっかりすると延々と回り続けます。公式にも、その状態を判別するための項目が入力に入っている旨の説明があるので、作るなら先に読んでおくほうが安全です。もうひとつ、hookの中からAIを呼ぶタイプもあります。便利ではあるのですが、走るたびにトークンを使います。
文章やレポートの仕事でのhooksの使いどころ
解説記事のほとんどは、コードを書く人に向けて書かれています。出てくる例も、整形ツール、検査ツール、テスト、といった開発の道具ばかりです。ただ、Claude Codeを文章やデータの仕事で使っている人にとっても、hooksは十分に使えます。私自身、コードを書くためにClaude Codeを開く日は多くありません。
思いつく範囲で、コードを書かない仕事でも役に立つものを挙げてみます。
①書き上がった原稿の形式チェック——記事をHTMLで書いているなら、書き換えた直後にタグの閉じ忘れと文字数を数えるだけでも十分です。人が最後にまとめて確認すると、どこかで見落としが出やすいです。
②台帳の更新忘れの検知——公開した記事を一覧表に追記する、という決まりごとがあるとします。Stopのタイミングで、その日触ったファイルと一覧表の更新日を突き合わせて、ずれていたら知らせる。忘れないようにする、ではなく、忘れても気づく形にします。
③外に出る操作の一時停止——投稿、送信、公開、集計用のデータ基盤への問い合わせのように、取り消しがきかない操作は、PreToolUseで一度止めて自分の目で見ます。1回で扱う量と実行の回数に上限を決めておく、という考え方は自動化の道具全般に共通していて、私は手元の自動化ツールでも同じ順番で枠をはめています。
④長い作業の完了通知——調査やまとめの作業は、待ち時間が読めません。終わったら音が鳴る、というだけで、待っている間に別の仕事ができます。
⑤表記の統一——媒体ごとに使わないと決めた言葉や、統一している表記があるはずです。書き換えた直後に本文を検索して、決めた語が混ざっていたら知らせる。私の場合は、使わないと決めた言い回しをいくつも抱えているので、目視ではなく検索で拾っています。直すのは自分でも、見つけるのを人がやる必要はありません。
向かないのは、判断が必要な仕事です。文章の良し悪しの判定や、方針の選択をhookに任せると、機械的に走るぶんだけ邪魔になります。良し悪しの判断はCLAUDE.mdやレビュー役のエージェントに任せて、決まった手順の実行はhooksに任せます。役割で割ると分かりやすいと思います。複数の役割に割る話はClaude Codeのエージェントを役割で分けて動かす方法に詳しく書いています。よければあわせて読んでみてください。
hooksの入れすぎと、減らすときの基準
hooksは、Claudeの判断を挟まずに毎回必ず走ります。裏を返すと、hookが重いぶんだけ、こちらの待ち時間がそのまま増えます。1回の実行が1秒でも、ファイルを50回書き換える作業なら50秒です。体感としては「なんとなく反応が鈍い」という形でしか現れないので、原因がhooksだと気づくまでに時間がかかります。hooksは足すのは一瞬ですが、遅さの原因として疑うのは最後になりがちです。
コストの話もしておきます。hookの中でAIやサブエージェントを呼べば、そのぶんトークンを使います。定額のプランで使っている場合、hookが走った回数だけ使用量の枠を削っていくことになります。金額の話はClaude Codeの料金プランと実際の請求額のほうにまとめてありますが、hookは頻度が読みにくいぶん、AIを呼ぶタイプは慎重に入れたほうが無難でしょう。
いま私のsettings.jsonに入っているhookは、PostToolUseに1つだけです。Stopの枠も用意してありますが、中身はまだ空のままにしています。イベントの一覧を見れば入れたくなるものはもっとありますが、増やすほど発火の順番と待ち時間が読めなくなるので、急いで埋めていません。増やすより、1つを確実に動かすほうが助かったというのが、しばらく回してみた実感です。
①しばらく発火した覚えがない ②発火はしているが、走った結果として何も変わっていない ③1回走るたびに、待たされたと体感する。どれかに当てはまったら、いったん外します。設定ごと消さずに別ファイルへ退避しておくと、また必要になったときに戻せます。外した状態でしばらく困らなければ、そのまま消して構いません。
hooksのセキュリティで気をつけること
hooksは、自分のパソコンで、自分の権限のまま、任意のシェルコマンドを走らせる仕組みです。便利さと危うさは同じところから来ています。書いた本人が意図した処理しか走らない、という前提が崩れると、そのまま被害になります。
私が決めているのは3つです。ひとつ、ファイルを消すコマンドをhookに書かない。移動までにする。ふたつ、パスワードやAPIキーをコマンドの中に直接書かない。設定ファイルは残りますし、記録にも残ります。必要なら、実行するときに自分で打ち込む形にします。みっつ、hookは軽く保つ。重い処理を毎回走らせるのは、待ち時間の面でも、途中で失敗したときの面でも損です。
もうひとつ気をつけたいのが、他の人が作ったプロジェクトを開くときです。プロジェクトの中のsettings.jsonにhooksが書いてあれば、それは自分のパソコンで、自分の権限のまま走る候補になります。中身を読まずに承認しない、というのが基本になります。
Claude Code hooksが動かないときの確認
設定したのに何も起きない、というのはよくあります。エラーが出るわけでもないので、原因が分かりにくいところです。私が順番に見ているのは次の6つです。
①登録されているか——Claude Codeの中で/hooksと打つと、いま読み込まれているhooksの一覧が出ます。ここに出てこなければ、書式が間違っているか、ファイルの場所が違います。
②セッションを開き直したか——起動中のセッションは、起動した時点の設定を持っています。settings.jsonを書き換えても、そのままでは反映されないことがあります。一度終了して入り直すのが確実です。
③イベント名とmatcherが合っているか——名前の綴りが1文字違うだけで、静かに無視されます。matcherに書いたツール名も同様です。
④パスが解決できているか——相対パスで書いたスクリプトは、実行時の場所によって見つからなくなります。$CLAUDE_PROJECT_DIRを使うか、絶対パスで書きます。あわせて、スクリプトに実行の許可が付いているかも確認します。
⑤入力の受け取り方——先に書いたとおり、ファイル名などは標準入力のJSONで渡ってきます。変数から取るつもりで書いていると、空のまま動いて何も起きません。
⑥シェルの起動ファイルが余計な出力をしていないか——.zshrcや.bashrcで何かを画面に表示していると、その文字がhookの出力に混ざって、JSONの解釈に失敗することがあります。原因として意外と多いので、心当たりがあれば疑う価値があります。
パソコンの側で詰まることもあります。Windowsで使う場合、macOSやLinux向けに書かれたサンプルのコマンドがそのままでは動かないことがあります。パスの区切り記号も違いますし、シェルの種類も違うからです。逆にmacOSでは、標準で入っているbashが3.2という古い版のままなので、新しい書き方を使うと構文の誤りとして弾かれます。サンプルを貼って動かないときは、まず手元のターミナルで同じコマンドを1行打ってみると切り分けが早いです。ターミナルでも動かないなら、hooksの書式ではなくコマンド側の問題です。
もうひとつ多いのが、呼んでいる道具がそのパソコンに入っていない場合です。解説記事のサンプルはjqのような小さな道具を前提にしていることが多く、入っていなければコマンドは黙って失敗します。エラーはClaudeの画面ではなくhookの出力側に出るので、気づきにくいところです。走った内容を確かめたいときは、会話の詳細表示に切り替えるとhookの出力まで追えます。
それでも分からないときは、デバッグ表示を付けて起動すると、どのhookがいつ走ったかが見えます。あとは、macOSで通知を出すタイプのhookなら、通知の許可が下りているかも確認してください。コマンドは正しく走っているのに、通知だけが表示されていない、ということがあります。
よくある質問
Q. Hooksの設定はチームメンバーと共有できますか?
A. できます。プロジェクトの中の.claude/settings.jsonに書いてバージョン管理に含めれば、そのプロジェクトを開いた全員に配られます。逆に、自分の手元でだけ試したいものは.claude/settings.local.jsonに書けば共有されません。共有するときに気をつけたいのは、受け取る側のパソコンで走るコマンドになる点です。自分のパソコンにしか入っていないツールを呼んでいると、他の人のところでは動きません。
Q. Hookのコマンドが失敗した場合、Claude Codeの動作はどうなりますか?
A. 返した終了コードによって変わります。2以外の失敗であれば、警告は出るものの作業そのものは進みます。2を返した場合は止まり、エラー出力に書いた文章がClaudeに渡って、Claudeがそれを読んだうえで次の行動を決めます。つまり「失敗=全部止まる」ではありません。止めたいときだけ、意図的に2を返す作りにしておくのがおすすめです。
Q. Git HooksとClaude Code Hooksは何が違いますか?
A. 考え方はよく似ていて、決まったタイミングで自分の処理を割り込ませる点は同じです。違うのは、引っかける相手です。Git Hooksが反応するのはgit(変更履歴を管理する道具)の操作で、コミットやプッシュの直前に走ります。Claude Code Hooksが反応するのはClaude Codeの操作で、ツールを使う前後や、応答が終わったタイミングです。両方を入れておくと、AIが書いた直後にひとつ、こちらが履歴に残す直前にもうひとつ、二段構えの検査になります。
Q. HooksとCLAUDE.mdのどちらを先に設定すべきですか?
A. 先にCLAUDE.mdだと思います。何をしてほしくて何をしてほしくないのかを文章で書いておかないと、hooksに何を移すべきかも決まらないからです。しばらく使っていると、書いたのに抜けるルールと、書けば守られるルールが分かれてきます。抜けるほうだけをhooksへ下ろす順番なら、hookの数が最小限で済みます。最初からhooksで固めようとすると、要らない停止が増えて作業が進まなくなります。
まとめ
hooksを入れて変わったのは、速さより「言わなくて済むようになったこと」でした。毎回同じ小言を書いていた時間が消えて、ルールを覚えておくのは私ではなく仕組みの側になりました。CLAUDE.mdを厚くしても届かなかったのは、そこが判断に委ねられていたからで、判断を挟まない場所に置き直しただけの話です。
始め方としては、壊れても困らないhookを1つだけ入れて、実際に走るのを目で確かめるところからで十分だと思います。イベント名や書式は変わっていくので、書く前に公式ドキュメントで今の一覧を見ておくと余計な回り道が減ります。重い処理と、取り返しのつかない処理を入れないこと。守るのはそのくらいです。
ルールを人が覚えておく状態から、仕組みが覚えている状態へ移すと、頭の中に置いておく荷物が1つ減ります。そうやって空いたぶんを何に使うのかのほうが、本当は面白い問いなのだと思います。私の場合は、まだ手が離せていない仕事を1つずつ渡していく作業に充てています。


