Claude Codeに「保存したら自動でフォーマット」を仕込んだら快適すぎた
はじめに
Claude Codeがファイルを編集するたびに、インデントがバラバラになっていることに気づく。
「.env は絶対に触るな」と書いたのに、次のターンで書き換えられていた。
CLAUDE.md に書いても、Claudeはお願いとして受け取るだけで、100%守ってくれるとは限らない。
そこで Hooks を使う。Hooks は CLAUDE.md の「お願い」をコードレベルの「強制」に変える仕組みだ。
- ファイル編集後に自動でコード整形を実行
- 機密ファイルへの変更を完全にブロック
- 全コマンドをログに記録
- 入力待ちになったらデスクトップ通知
この記事では、Hooks の仕組みと実践的な設定例を解説する。
Hooks とは
Hooks は、Claude Code のライフサイクルの様々なポイントで実行されるユーザー定義のシェルコマンド。
あなたの指示
↓
Claude が行動を決定
↓
[PreToolUse Hook] ← ツール実行前にチェック(ブロック可能)
↓
ツール実行(ファイル編集、コマンド実行など)
↓
[PostToolUse Hook] ← ツール実行後に自動処理(フォーマット等)
CLAUDE.md との違い:
| CLAUDE.md | Hooks | |
|---|---|---|
| 性質 | お願い(提案) | 強制(コード) |
| 実行保証 | なし(無視される場合あり) | 100%(シェルコマンドとして実行) |
| 用途 | ルール、慣習、好み | 自動化、ガードレール、通知 |
設定方法
設定ファイルの場所
| ファイル | 用途 |
|---|---|
~/.claude/settings.json |
全プロジェクト共通(個人設定) |
.claude/settings.json |
プロジェクト共有(Git管理) |
.claude/settings.local.json |
ローカル専用(Git管理外) |
基本構造
{
"hooks": {
"イベント名": [
{
"matcher": "ツール名パターン",
"hooks": [
{
"type": "command",
"command": "実行するコマンド"
}
]
}
]
}
}
/hooks コマンドで設定する
設定ファイルを直接編集する代わりに、Claude Code 内で /hooks と入力すると対話的に設定できる。
フックの種類
よく使うものを中心に紹介する。
PreToolUse(ツール実行前)
ツールが実行される前にチェックする。ブロックも可能。
使い道:機密ファイルの保護、コマンドの検証
PostToolUse(ツール実行後)
ツールが正常に完了した直後に実行する。
使い道:自動フォーマット、lint実行
Notification(通知)
Claude Code が入力待ちや権限確認を求めている時に発火する。
使い道:デスクトップ通知、サウンド再生
Stop(停止時)
Claude Code が応答を終了した時に実行する。
使い道:完了通知、セッションログの保存
その他
| フック | タイミング |
|---|---|
| UserPromptSubmit | ユーザーがプロンプトを送信した直後 |
| SessionStart | セッション開始・再開時 |
| SessionEnd | セッション終了時 |
| PreCompact | コンパクト実行前 |
| SubagentStop | サブエージェント終了時 |
マッチャー(matcher)の仕組み
マッチャーで「どのツールに対して発火するか」を指定する。大文字小文字を区別する。
| パターン | マッチ対象 |
|---|---|
Write |
Write ツールのみ |
Edit|Write |
Edit または Write |
Bash |
Bash コマンドのみ |
Notebook.* |
Notebook 系全て |
* または ""
|
全ツール |
MCP ツールの場合は mcp__サーバー名__ツール名 のパターンに従う。
実践的な設定例
例1:ファイル編集後に自動フォーマット
TypeScript ファイルを Prettier で自動フォーマットする。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.ts$'; then npx prettier --write \"$file_path\"; fi; }"
}
]
}
]
}
}
仕組み:
-
EditまたはWriteツールが実行された後に発火 - stdin(標準入力)から渡された JSON を
jqで解析し、ファイルパスを取得 -
.tsファイルなら Prettier を実行
例2:機密ファイルへの変更をブロック
.env、package-lock.json、.git/ への編集を完全にブロックする。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | { read fp; case \"$fp\" in *.env|*.env.*|package-lock.json|.git/*) echo \"Protected file: $fp\" >&2; exit 2;; esac; }"
}
]
}
]
}
}
ポイント:終了コード 2 を返すと、そのツール呼び出しがブロックされる。stderr(標準エラー出力:エラーメッセージ用の出力先)のメッセージが Claude にフィードバックされる。
例3:入力待ちのデスクトップ通知
Claude Code が入力を待っている時に通知を送る。離席時に便利。
Windows(PowerShell経由):
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code is waiting for input')\""
}
]
}
]
}
}
macOS:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code is waiting\" with title \"Claude Code\"'"
}
]
}
]
}
}
例4:全 Bash コマンドをログに記録
Claude Code が実行した全コマンドを記録する。何をしたか後から確認できる。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\"[\" + (now | strftime(\"%Y-%m-%d %H:%M:%S\")) + \"] \" + .tool_input.command' >> ~/.claude/bash-command-log.txt"
}
]
}
]
}
}
終了コードの意味
Hook の終了コードで動作が変わる。
| 終了コード | 動作 |
|---|---|
| 0 | 成功。stdout は詳細モードで表示 |
| 2 | ブロック。stderr がエラーメッセージとして Claude にフィードバック |
| その他 | エラーだがブロックしない。stderr が詳細モードで表示 |
PreToolUse で終了コード 2 を返すと、そのツール呼び出しの実行を阻止できる。これが「ガードレール」の仕組み。
注意点
セキュリティ
Hooks は任意のシェルコマンドを自動実行する。つまり:
- ユーザーアカウントがアクセスできる全ファイルを変更・削除可能
- 悪意のあるスクリプトが仕込まれると危険
対策:
- 入力を検証する(stdin の JSON を盲目的に信頼しない)
- シェル変数は常にクォートする(
"$VAR") - 絶対パスを使用する
-
.envや.git/はスキップする
設定の反映タイミング
- Hook の設定は起動時にスナップショットされる
- セッション中に設定を変更しても即座には反映されない
- 変更が検出されると警告が表示され、
/hooksで確認が必要
タイムアウト
- デフォルト 60秒 でタイムアウト
-
"timeout": 30のように個別に設定可能
まとめ
| ポイント | 内容 |
|---|---|
| Hooks とは | ツール実行前後に自動で走るシェルコマンド |
| CLAUDE.md との違い | 「お願い」→「強制」 |
| 主な用途 | 自動フォーマット、ファイル保護、ログ、通知 |
| ブロックの方法 | PreToolUse で終了コード 2 を返す |
| 設定ファイル |
~/.claude/settings.json or .claude/settings.json
|
覚えておくこと:
CLAUDE.md に「〜しないで」と書いて守られなかったら、
それは Hook で強制すべきルール。
Discussion