Claude Codeでファイルを編集したりコマンドを実行したりするとき、「その前に自動でlintをかけたい」「特定のファイルへの書き込みを禁止したい」と思ったことはありませんか?
そんな要望に応えるのが「フック(Hooks)」機能です。Claudeのツール実行やセッションイベントの前後に、あなたが定義したシェルコマンドを自動で実行できます。
みなさんこんにちは! 今日はClaude Codeの「フック」機能について解説するよ!
フックって…釣り針のこと? 何かを引っかけるの?
プログラミングでの「フック」は、特定のイベントに処理を「引っかける」仕組みです。Gitフックと同じ概念で、Claude Codeの動作の前後にカスタム処理を挟めます。
あ、Gitのpre-commitフックみたいなやつか! Claudeがファイル書く前に何か実行できるってこと?
まさにその通りです。ファイル編集の前後、コマンド実行の前後、セッションの開始・停止など、様々なタイミングで処理を挟めます。
フック(Hooks)とは?
フックは、Claude Codeの各種イベントに対してユーザー定義のシェルコマンドを自動実行する仕組みです。2025年6月に導入され、Claude Codeの自動化をさらに強力にする機能として注目されています。
フックの核心は「Claudeのツール実行パイプラインに割り込める」こと。例えば:
- ファイル保存後に自動でフォーマッターを実行
- 特定のファイル(
.envなど)への編集をブロック - コマンド実行前にセキュリティチェック
- セッション開始時に環境のセットアップ
フックの重要な特徴: フックは「ユーザーの許可システム」をバイパスして実行されます。つまり、通常はユーザー承認が必要なツール操作でも、フックで定義した処理は自動で実行されます。
その代わり、フックの設定自体はsettings.jsonに書く必要があり、CLAUDE.mdからは設定できません(セキュリティ上の理由)。
フックのイベント一覧
Claude Codeでは、以下のイベントタイミングでフックを実行できます。
ツール実行系
最もよく使うのがこの2つです。ツール実行の「前」と「後」に処理を挟めます。
PreToolUse — ツール実行の「前」に発火(ブロック可能)
PostToolUse — ツール実行の「後」に発火(結果をフィードバック可能)
PreToolUseが特に強力です。終了コード2を返すとツールの実行自体をブロックできます。セキュリティガードとして非常に有効です。
セッション系
PreCompact — コンテキスト圧縮の前
PostCompact — コンテキスト圧縮の後
SessionStart — セッション開始時
SessionPause — セッション一時停止時
SessionResume — セッション再開時
Stop — Claudeの応答完了時
SessionStartって、Claude Codeを起動するたびに実行されるの? それ便利そう!
はい。例えばSessionStartでgit pullを自動実行して、常に最新のコードで作業を開始する、といった使い方ができます。
通知系
Notification — Claudeが通知を送信するとき
長時間タスクの完了通知などをカスタマイズできます。デスクトップ通知やSlack通知を独自に実装したい場合に使います。
対象ツール名(matcherで指定可能):
Write, Edit, Bash, Read, Glob, Grep, WebFetch, WebSearch, Task, NotebookEdit など。
ワイルドカードも使用可能: "*"で全ツールにマッチします。
フックの設定方法
フックはsettings.jsonに記述します。Claude Codeの設定ファイルには3つのレベルがあります。
設定ファイルの場所
# ユーザー設定(全プロジェクト共通)
~/.claude/settings.json
# プロジェクト設定(チーム共有・gitにコミット可能)
.claude/settings.json
# ローカル設定(個人用・gitignore推奨)
.claude/settings.local.json
3つもあるの? どれに書けばいいんだろう…
個人の開発環境で使うフックは~/.claude/settings.jsonに。チームで共有したいルールは.claude/settings.jsonに。自分だけのローカル設定は.claude/settings.local.jsonに書きます。
基本的な書き方
フックの設定はJSON形式です。以下が基本構造になります。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "echo 'ファイル編集前のチェック'"
}
]
}
]
}
}
ふむふむ…matcherでどのツールに対して発火するか指定して、hooksの中に実行するコマンドを書くんだね。
正確です。各フィールドの意味を整理しましょう。
フック設定の主なフィールド:
matcher: 対象ツール名("Edit", "Bash", "Write"など)。省略で全ツール。
hooks[].type: "command"(シェルコマンド実行)が基本。
hooks[].command: 実行するシェルコマンド。
hooks[].timeout: タイムアウト(ミリ秒)。デフォルト60000ms。
hooks[].async: trueで非同期実行(結果を待たない)。
/hooks コマンドで簡単設定
JSONを手で書くのが面倒な場合は、Claude Code内で/hooksコマンドを使えば対話的にフックを設定できます。
# Claude Codeのプロンプトで
> /hooks
イベントの選択、マッチャーの設定、コマンドの入力をステップバイステップで案内してくれます。
あ、よかった〜! JSON手書きは不安だったけど、対話形式で設定できるなら安心だね。
終了コードとデータの流れ
フックの真の力は、終了コードによる制御とデータのやり取りにあります。
終了コードの意味
終了コード 0 → 成功(処理を続行)
終了コード 1 → エラー(Claudeにエラーを通知、処理は続行)
終了コード 2 → ブロック(ツール実行を中止)※PreToolUseのみ
終了コード2で「ブロック」できるのがポイントだね! Claudeに「それやっちゃダメ」って言えるんだ。
その通りです。さらに、stdoutに出力した内容はClaudeへのフィードバックとして渡されます。ブロックした理由を説明すれば、Claudeは別のアプローチを試みます。
環境変数で入力データを受け取る
フックのコマンドは、実行コンテキストに関する情報を環境変数として受け取れます。
# PreToolUse / PostToolUse で利用可能な環境変数
CLAUDE_TOOL_NAME — 実行されるツール名(Edit, Bash等)
CLAUDE_TOOL_INPUT — ツールへの入力(JSON文字列)
CLAUDE_SESSION_ID — セッションID
CLAUDE_PROJECT_DIR — プロジェクトディレクトリ
# PostToolUseのみ
CLAUDE_TOOL_OUTPUT — ツールの実行結果
おお! CLAUDE_TOOL_INPUTからどのファイルを編集しようとしてるか分かるんだ! これでファイルパスのチェックができるね!
よい着眼点です。CLAUDE_TOOL_INPUTはJSON文字列なので、jqコマンドでパースして使うのが一般的です。
実践例: すぐに使えるフック集
ここからは実際にプロジェクトで使える実践的なフック例を紹介します。
例1: ファイル保存後に自動フォーマット
最も人気の高いユースケースです。Claudeがファイルを編集した後に、自動でフォーマッターを走らせます。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $CLAUDE_TOOL_INPUT | jq -r '.file_path // .file_name // empty') && [ -n \"$FILE\" ] && npx prettier --write \"$FILE\" 2>/dev/null || true"
}
]
}
]
}
}
これいいね! Claudeが書いたコードが自動的にPrettierで整形されるんだ。手動で走らせる手間がなくなる!
matcherに"Write|Edit"とパイプ区切りで書くと、WriteまたはEditのどちらのツールでも発火します。末尾の|| trueはフォーマッター未設定の環境でエラーにならないための安全策です。
例2: 機密ファイルの編集をブロック
セキュリティ上、Claudeに触られたくないファイルを保護します。.envや認証情報ファイルへの編集を事前にブロックする例です。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $CLAUDE_TOOL_INPUT | jq -r '.file_path // .file_name // empty') && case \"$FILE\" in *.env|*.env.*|*credentials*|*.pem|*.key) echo \"BLOCKED: $FILE は保護されたファイルです\" && exit 2;; esac"
}
]
}
]
}
}
これは大事だ…! .envをうっかり書き換えられたら大変だもんね。exit 2で確実にブロックされるのがポイントかぁ。
echoで出力したメッセージがClaudeにフィードバックされるため、Claudeは「なぜブロックされたか」を理解して別の方法を提案してくれます。
例3: 危険なコマンドの実行を防止
Bashツール経由でrm -rfやgit push --forceなどの危険なコマンドが実行されるのを防ぎます。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(echo $CLAUDE_TOOL_INPUT | jq -r '.command // empty') && echo \"$CMD\" | grep -qE '(rm\\s+-rf|git\\s+push\\s+--force|drop\\s+table)' && echo \"BLOCKED: 危険なコマンドが検出されました: $CMD\" && exit 2 || true"
}
]
}
]
}
}
rm -rfとかgit push --forceを自動でブロック! これ、bypassPermissionsモードで使ってる人には必須じゃない?
重要な指摘です。全許可モードで運用する場合、フックによるガードレールは事実上唯一の防御線になります。必ず設定することを推奨します。
例4: セッション開始時の環境セットアップ
セッション開始時に自動で環境を整える例です。
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "git fetch origin --prune 2>/dev/null; echo 'リモートブランチを同期しました'"
}
]
}
]
}
}
例5: Slack通知
Claudeの応答が完了したときにSlack通知を送る例です。長時間タスクの完了を待つ場合に便利です。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -X POST $SLACK_WEBHOOK_URL -H 'Content-Type: application/json' -d '{\"text\": \"Claude Codeのタスクが完了しました\"}' > /dev/null",
"async": true
}
]
}
]
}
}
Slackに通知飛ばせるの最高! 別の作業してる間にClaude任せて、終わったらSlackで知らせてもらえるんだ!
"async": trueを設定していることに注目してください。通知送信はClaudeの処理をブロックする必要がないため、非同期で実行します。
セキュリティの注意点
フックは強力な機能ですが、セキュリティ面での注意も必要です。
フックってシェルコマンドを自動実行するんだよね…。悪意のあるフックが仕込まれたら危なくない?
良い質問です。Anthropicもその点を重視しており、いくつかの安全機構があります。
安全機構
- CLAUDE.mdからフック設定不可: フックは
settings.jsonでのみ設定できます。プロンプトインジェクション経由での設定変更を防止 - プロジェクト設定のフックは承認が必要:
.claude/settings.jsonに書かれたフックは、初回実行時にユーザーの明示的な承認が求められます - stdoutのみがフィードバック: フックのstdoutだけがClaudeに渡されます。stderrは渡されないため、意図しない情報漏洩を防げます
ベストプラクティス
- フックのコマンドは短く保つ。複雑なロジックは外部スクリプトに分離する
timeoutを適切に設定して、フックの暴走を防ぐ- 機密情報をstdoutに出力しない(Claudeに渡されるため)
- プロジェクト設定のフックをgitに含める場合、チームメンバーにフックの存在を共有する
- 定期的にフック設定を見直し、不要なフックを削除する
フックの設定レベルと信頼性:
ユーザー設定(~/.claude/settings.json): 最も信頼度が高い。自動実行される。
プロジェクト設定(.claude/settings.json): git共有可能。初回は承認が必要。
ローカル設定(.claude/settings.local.json): 個人用。gitignore推奨。自動実行される。
マネージド設定(企業管理): 管理者が全社に配布。ユーザーは変更不可。
よくある質問
ここからはよくある質問をまとめるよ!
Q: フックとCLAUDE.mdの指示は何が違う?
CLAUDE.mdの指示は「Claudeへのお願い」であり、Claudeが判断して従います。一方、フックは「システムレベルの強制」であり、Claudeの判断に関係なく必ず実行されます。機密ファイルの保護など、確実に守りたいルールはフックで実装しましょう。
Q: フックが失敗したらどうなる?
終了コード1(エラー)の場合、エラーメッセージがClaudeに通知されますが処理は続行されます。フック自体がクラッシュした場合もClaude Codeの動作は停止しません。タイムアウト(デフォルト60秒)を超えた場合はフックが強制終了されます。
Q: 複数のフックが同じイベントに設定されている場合は?
設定ファイルに記述された順番で順次実行されます。途中のフックが終了コード2(ブロック)を返した場合、後続のフックは実行されずにツール実行がキャンセルされます。
補足すると、異なる設定レベル(ユーザー・プロジェクト・ローカル)のフックは全てマージされて実行されます。ユーザー設定のフックが先に実行されます。
Q: フックのデバッグ方法は?
フックのコマンドにログ出力を追加するのが効果的です。stderrに出力すればClaudeには渡らず、ターミナルのログで確認できます。
# デバッグ用: stderrにログを出力
echo "DEBUG: tool=$CLAUDE_TOOL_NAME input=$CLAUDE_TOOL_INPUT" >&2
まとめ
Claude Codeのフック機能は、AIエージェントの動作を細かく制御するための強力な仕組みです。
- 8種類のイベント: PreToolUse、PostToolUse、SessionStart、Stop、Notificationなど
- 終了コード2でブロック: セキュリティガードとして危険な操作を事前に防止
- 環境変数で入力データ取得: ツール名、入力JSON、セッションIDなどを受け取れる
- 3つの設定レベル: ユーザー、プロジェクト、ローカル設定で柔軟に管理
- 実践的な使い方: 自動フォーマット、ファイル保護、危険コマンド防止、Slack通知など
特にbypassPermissionsモードを使っている開発者には、フックによるセキュリティガードレールの設定を強く推奨します。まずは「機密ファイルの編集ブロック」から始めてみてはいかがでしょうか。
今日はここまで! フック、最初は難しそうだったけど、使い方が分かると「これ設定しないと不安」ってなるね。
お疲れさまでした。フックは「保険」のようなもの。問題が起きる前に設定しておくことに意味があります。
次回はMCPサーバーについて解説するよ! Claude Codeをさらにパワーアップさせる方法だから、お楽しみに! ばいばい〜!