シリーズ記事
- Claude Code ゼロイチ(0→1)編
- Claude Code CLAUDE.md編
- Claude Code Hooks編 ← 本編
- Claude Code メモリ編
- Claude Code Skills編
- Claude Code サブエージェント編
はじめに
前回は CLAUDE.md の設定をしました。次は Hook の設定をしていきましょう。
Hooks について公式ドキュメントには以下のように記載されてます。
フックは Claude のワークフローの特定のポイントで自動的にスクリプトを実行します。CLAUDE.md の指示は勧告的ですが、フックは決定的で、アクションが確実に実行されることを保証します。
Claude はあなたのためにフックを書くことができます。「すべてのファイル編集後に eslint を実行するフックを書く」 または 「migrations フォルダへの書き込みをブロックするフックを書く」 のようなプロンプトを試してください。/hooks を実行して対話的に設定するか、.claude/settings.json を直接編集します。
「CLAUDE.md の指示は勧告的(advisory)」とは、Claude(LLM)が内容を読んで参考にするが、忘れたり無視したりする可能性があるということです。一方「Hooks は決定的(deterministic)」とは、LLM の判断に関係なく、設定した処理が必ず実行される ことを意味するようです。
たとえば CLAUDE.md に「コミット前に ktlint を実行してください」と書いても Claude がそれスルーしてしまうことがありますが、Hooks に設定すれば git commit のたびに確実に実行されます。
Hooks はどうやらgithooks みたいな機能のようです。
本シリーズの記事は基本的に Claude Code と会話しながら Claude Code をカスタマイズしていきますが、同時に公式ドキュメントも参考にしています。本記事を読んだ後に、公式ドキュメントも合わせて読むと Claude Code の理解がより深まると思います。
参考
Hooks の設定
今回も Claude Code と会話しながら進めていきます。公式ドキュメントには「/hooks を実行して対話的に設定する」とありますが、私は Hooks についての理解があり、何をするかある程度決まっていないと /hooks 実行後に Claude Code とまともに対話できない と感じました。 なので Claude Code に身を委ねるべく雑に以下の命令を出してみます。
このプロジェクトに適した Claude Code の Hooks 設定を提案をして下さい
プロジェクト走査した後以下のメッセージが表示されました。
⏺ Hooks の調査結果を踏まえて、このプロジェクトに適した設定を提案します。
──────────────────────────────────────────────────────────────────────────
← ☐ Hook の目的 ☐ 共有範囲 ✔ Submit →
Hooks でどのような自動化を実現したいですか?
❯ 1. [ ] ktlint 自動整形 .kt ファイル編集後に自動で ktlintFormat を実行してコードスタイルを統一
2. [ ] 保護ファイルのガード
secrets/、local.properties、.env などの機密ファイルの誤編集をブロック
3. [ ] 危険コマンドの防止
git push --force、rm -rf、./gradlew clean など破壊的コマンドをブロック
4. [ ] macOS 通知
長時間タスク完了時にデスクトップ通知を表示
──────────────────────────────────────────────────────────────────────────
6. Chat about this
7. Skip interview and plan immediately
Enter to select · Tab/Arrow keys to navigate · Esc to cancel
私はプロジェクトに ktlintを適用しているので ktlint の自動実行を提案されました。ktlint とは別の linter をプロジェクトに設定している場合はその linter の自動実行を提案するのだと思います。
1-4 全て適用することにします。
何度か Claude Code と会話をし以下の設定が .setting.json に記載されました。
| Hook | イベント | 動作 |
|---|---|---|
| 機密ファイル保護 | PreToolUse (Edit/Write) | secrets/、local.properties 等への書き込みをブロック |
| 危険コマンドブロック | PreToolUse (Bash) | force push、hard reset 等をブロック |
| ktlint 自動整形 | PreToolUse (Bash) | git commit 前に ktlintFormat → git add -u を実行 |
| macOS 通知 | Stop | 処理完了時にネイティブ通知を表示 |
settings.json に "hooks" をキーにした Hooks 設定が書き込まれました。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); FILE_PATH=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // empty'); if echo \"$FILE_PATH\" | grep -qE '(composeApp/secrets/|local\\.properties|google-services\\.json|\\.env)'; then echo '機密ファイルへの変更はブロックされました' >&2; exit 2; fi"
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command // empty'); if echo \"$CMD\" | grep -qE '(push\\s+--force|push\\s+-f|reset\\s+--hard|clean\\s+-fd|rm\\s+-rf\\s+/)'; then echo '危険なコマンドはブロックされました' >&2; exit 2; fi"
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command // empty'); if echo \"$CMD\" | grep -qE 'git\\s+commit'; then cd /Users/xxxx/your-project && ./gradlew ktlintFormat --rerun-tasks 2>&1 && git add -u; fi"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"応答が必要です\" with title \"Claude Code\" sound name \"Glass\"'"
}
]
}
]
}
}
settings.json に書き込まれた Hooks 設定は何となく意味が分かる程度で良いと思います。細かく"ここはこういう意味だ" と理解する必要はありません。Hooks 設定は AI にお願いすればよく、あなたが手書きすることは無いのですから😙 例えば Claude Code に以下のように依頼すれば settings.json が作られるはずです。
このプロジェクトの Claude Code Hooks に機密ファイルを保護する設定を追加して下さい。
補足
settings.json の意味はわからなくてもいいとはいえ、 PreToolUse の Bash matcher が2つあることに違和感を感じている方もいるかもしれません。同じ matcher は複数設定でき、それぞれ独立した Hook として動作します。今回は「危険コマンドブロック」と「ktlint 自動整形」を別々の Hook として分けることで、役割を明確に分離しています。
まとめ
実際に Hooks を作ってみることで Hooks とは何かを何となく理解できました。次からは作りたい Hooks を念頭に置いて公式ドキュメント通り /hooks コマンドで Hooks を作れそうです。
ところで、Hooks はシステム開発全体をより効率的にする目的で使うものであり、「設計書に基づいてコードを書き、システムを実装する」の目的のために使うものでは無さそうです。コーディング補助というよりエンジニアリング補助という感じでしょうか。
チームで開発する場合は、コーディング規約の強制やプロセス自動化として真価を発揮しそうです。個人開発では ktlint 自動整形のような規約強制フックは優先度が低いかもしれませんが、機密ファイル保護や危険コマンドブロックは AI エージェントによる意図しない操作を防ぐセーフガードとして、個人開発でも有効と思います。