hooks による自動化設計。Claude Code の動きにタイミングを仕込む
ハーネス設計シリーズ3本目は、permissions が決めた境界の中で「何を・どのタイミングで自動的に動かすか」の話です。hooks は仕掛けが強力な分、設計の良し悪しがそのまま作業の体感に出ます。個別機能の解説ではなく、設計の地図を整理します。
はじめに
Step 5 ハーネス設計シリーズの3本目です。1本目「Claude Code のハーネスとは何か」で全体像を、2本目「permissions と settings.json の設計」で境界の引き方を扱いました。本記事ではその境界の中で、何を・どのタイミングで自動的に動かすか——hooks の設計を扱います。
hooks の 書き方そのもの は、すでに別記事で扱い終えています。概念は「Claude Hooks とは何か」、最小例の書き方は「Claude Hooks の基本の書き方」を参照してください。本記事はそれらの 次の段階——書ける前提で、どう設計するか を整理します。
読み終えたあとには、自分が日々 Claude に頼んでいる「いつもの後処理」を、hooks に置き換える判断軸がつかめるはずです。
hooks で何ができるかの振り返り
軽く振り返りだけしておきます。hooks は、特定のイベントが起きたときに、決まったシェルコマンドを自動で走らせる しくみです。書き場所は settings.json の中。Claude が判断するのではなく、Claude Code 本体(ハーネス)が機械的に実行 します。
イベント種別は PreToolUse(ツール実行の直前)、PostToolUse(直後)、UserPromptSubmit(プロンプト送信時)、Stop(応答終了時)など複数あります。詳細は既存記事のとおりです。
ここから先は、これらの素材をどう組み合わせて自分のハーネスに仕込むか、の話に絞ります。
自動化の3軸:何のための hooks か
hooks を設計するときは、「何のためにこれを仕込むのか」 を最初にはっきりさせます。目的が曖昧なまま hooks を増やすと、いつの間にか小さな矛盾が積み上がり、Claude の動きが読みにくくなります。
目的は大きく3つの軸に分かれます。
軸1:確実性
「Claude の判断に委ねず、毎回必ずやらせたい」という軸です。Claude にお願いベースで頼むと、忘れることがあります。hooks にしてしまえば、条件が合えば100%発火します。
例:「ファイル編集後は必ず npm run lint を走らせる」「.ts を保存したら必ず型チェックをかける」など、毎回の品質ゲート がここに該当します。
軸2:観察
「後で振り返りたい・ログを残したい」という軸です。Claude との会話は流れていきますが、自分のプロンプトやツール実行の履歴をファイルに残しておくと、あとから「あの依頼、どう書いたっけ」を遡れます。
例:「自分のプロンプトをすべて ~/.claude/logs/ に追記する」「Bash 実行のたびにコマンドと終了コードを記録する」など、学習や振り返りのための痕跡作り がここです。
軸3:ガード
「取り返しのつかない操作を、最後の砦で止めたい」という軸です。permissions の deny でも止められますが、hooks の方が より細かい条件 を書けます。コマンド全文の中に特定のパターンが含まれていたらブロック、といった判定が hooks なら可能です。
例:「Bash で git push --force が出たら止める」「Edit のたびに対象ファイルが本番設定ファイルでないか確認する」など、最終防衛線 としての使い方です。
設計を始めるときは、まずこの どの軸の話をしているのか を意識します。3軸が混ざった hooks を1本に詰め込むと、保守が難しくなります。
イベント選びの指針
hooks を仕込むイベント種別は、「いつ動かしたいか」から逆算する と迷いません。
| やりたいこと | 選ぶイベント |
|---|---|
| ツールが動く前に止めたい・確認したい | PreToolUse |
| ツールが動いた後に何かしたい(lint、整形、通知) | PostToolUse |
| ユーザー入力を起点に何かしたい(ログ、定型文挿入) | UserPromptSubmit |
| Claude の応答が終わったときに何かしたい(通知音) | Stop |
| 会話の自動圧縮の前に何かしたい(スナップショット) | PreCompact |
迷いやすいのは PreToolUse と PostToolUse の使い分けです。判断軸はシンプルで、「動く前に止めたい/確認したい」なら Pre、「動いた結果を受けて何かしたい」なら Post です。
WordPress のアクションフックを触ったことがある方なら、save_post の前後の pre_post_update と save_post の関係に近い感覚で考えると掴みやすいかもしれません。何かが起きる前に介入するか、起きた結果を受けるか。判断のしどころはここに集約されます。
ガード系(軸3)は基本的に PreToolUse、品質ゲート系(軸1)は基本的に PostToolUse、観察系(軸2)は UserPromptSubmit か Stop——という大まかな対応を覚えておくと、最初の選択がぶれません。
matcher の設計
各イベントには matcher で 「どのツールが使われたとき」 を絞れます。これを使いこなさないと、hooks がすべてのツールで発動してしまい、毎回の操作が重くなります。
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "npm run lint" }]
},
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "echo $TOOL_INPUT >> ~/.claude/logs/bash.log" }]
}
]
matcher は正規表現が書けます。"Edit|Write" で「Edit と Write の両方」、""(空文字)で「全ツール」、"Read" で「Read のみ」というふうに、目的に応じて狭く絞る のが基本です。
設計上の重要な判断は、「対象を最小に絞る」 こと。最初から全ツール対象で書くと、Read だけしている軽い操作のたびに lint が走ったりして、体感速度が落ちます。「lint が必要なのは Edit と Write だけ」のように、動かす理由のあるツールだけに絞る 設計を心がけます。
ESLint の overrides で対象ファイルを絞るのと同じ発想です。広く適用してから絞るのではなく、最初から狭く適用する のが運用コストを抑えるコツです。
設計の手順:3ステップ
実際に hooks を設計するときは、次の順で進めると無駄が出ません。
Step 1. 「毎回手で頼んでいる後処理」を書き出す
まず、自分が Claude に 繰り返し依頼している後処理 を紙に書き出します。「ファイル編集後の lint」「コミット前の型チェック」「危険コマンドの確認依頼」——いつもの口癖を全部出してみると、5〜10個は出てくるはずです。
これらは hooks 化の有力候補 です。「毎回頼んでいる」は、すでに自動化の余地が見えているサインです。
Step 2. それぞれを3軸に分類する
書き出したリストを、確実性 / 観察 / ガード の3軸に振り分けます。「ファイル編集後の lint」は確実性、「プロンプトのログ取得」は観察、「rm -rf のブロック」はガード——というふうに。
軸が決まれば、選ぶイベントもおおよそ決まります(前述の対応表)。この振り分けを飛ばすと、なぜその hooks があるのか自分でも忘れる ので、メモでも構わないので必ずやっておきます。
Step 3. 最小から仕掛ける
最初の hooks は、副作用のない読み取り系 から入れるのが安全です。具体的には、PostToolUse で git diff --stat を出すような「結果を表示するだけ」の hooks です。
慣れたら次に観察系(ファイル追記)、その次にガード系(PreToolUse でのブロック)と進めます。最初からブロック系を書くと、思わぬところで作業が止まり ます。「rm を全部止める」と書いた直後に、自分が削除したいファイルまで止められて、設定をいじる羽目になる——という事故が起きやすい順序です。
「最小から、慎重に、徐々に」が hooks 設計の鉄則です。CI でいうと、最初から set -e で全部落とす設定を書かず、まずは出力を見るだけのジョブを足すあの感覚に近いです。
ありがちな失敗
ふたつだけ、ありがちな失敗を共有しておきます。
ひとつめは hooks にロジックを書きすぎる こと。command の中に if 文や for 文を詰め込むと、すぐに読めなくなります。複雑になるなら シェルスクリプトを別ファイルに切り出して呼ぶ 方が、後で自分が読み返せます。settings.json には呼び出し1行だけ、ロジックは外、という分け方が長く保ちます。
ふたつめは 失敗時の挙動を考えていない こと。hooks の中身が落ちたとき、Claude Code 本体は何事もなかったかのように進むのか、止まるのか。PreToolUse でガード系を組むなら、ブロックの仕方は exit code で制御 します。0 なら通す、非 0 なら止める、といったルールを意識せずに書くと、「ガード hooks を入れたつもりが素通りしていた」ということが起きます。書く前に exit code の設計まで含めておくと安全です。
まとめと次回
要点を振り返ります。
- hooks の設計は 3軸(確実性 / 観察 / ガード)から始める
- イベント選びは 「いつ動かしたいか」から逆算 する
matcherは 最小に絞る。広く適用してから絞るのではなく、最初から狭く- 設計手順は 書き出す → 3軸分類 → 最小から仕掛ける
- 副作用のないものから入れる。ブロック系は最後
- ロジックは外部スクリプトへ、
settings.jsonは呼び出しだけ - exit code の設計を忘れない
次回(4本目・最終回)は、ハーネスの最後のひと品——「subagents と skills の組み合わせ」を扱います。境界(permissions)と仕掛け(hooks)の上に、役割分担の設計 を載せると、ハーネスがひとつの作業環境として完成します。続けて読むと、本シリーズの最初に出した「7部品が束になる」絵が、自分の手元で組み立てられる感覚に変わるはずです。
WordPressを実際に動かしてきたサーバー:ロリポップ
Claude Code でWordPressサイトを組み立てるとき、最初に置く先として無理のないレンタルサーバー。月数百円から始められ、WordPressの自動インストールにも対応しています。設定で詰まりがちな初期段階の時間をかなり減らせます。