毎回ファイルを保存してからlintをかけ、formatを当てて、testを走らせる。この3ステップ、1日のうちに何回繰り返していますか?Claude CodeのHooks機能に設定を1回書けば、以降はファイル編集の直後に全部自動で走ります。jqのインストールも不要。WindowsのPowerShellでそのまま動く手順をこれから書きます。
この記事でやること
Claude CodeのHooks機能を使ってファイル編集後にlint・format・testを自動実行する設定を完了させます。Windows環境のPowerShellで動くコピペ前提の具体例を中心に進めます。設定後の確認とテスト手順も最後までカバーします。
Hooksとは——ざっくり言うと「ファイル編集後に自動でコマンドを走らせる仕組み」
Hooksは、Claude Codeが特定のタイミングでユーザー定義のコマンドを自動実行する仕組みです。LLMの判断に依存せず、決められた条件を満たしたら確実にコマンドが走る——これが「deterministic制御」と呼ばれる部分です。
今回はこの中からPostToolUseイベントを使います。Claude CodeがEditまたはWriteツールでファイルを編集した直後に、指定したコマンドが自動で走る仕組みです。手動でファイルを保存した時ではなく、Claude Code自身がファイルを編集したタイミングでのみ発火します。
matcherには正規表現パターンを指定できます。Edit|Writeはパイプ(|)で区切られたパターンで、「EditまたはWrite」を意味します。
Claude Codeがファイルを編集した直後に、裏でPrettierが走ってコードが整形される——その仕組みです。設定は短くて1行、長くても5行程度。
設定ファイルの用意から始めます。
事前に必要なもの
設定を始める前に、以下が揃っているか確認してください。
- Claude Codeがインストール済みであること
- プロジェクトにlint・format・testツールが導入済みであること(例:Prettier、ESLint、pytest、vitestなど)
- 設定ファイル(
settings.json)が存在すること——確認方法はこのあと説明します - Windows PowerShell環境であること(bashではなくPowerShellで動く例を紹介します)
jqは不要です。 この記事ではPowerShellだけでfile_pathを抽出する方法を紹介するので、追加のツールインストールはありません。
設定ファイルのパスは2種類あります。
- プロジェクト単位(おすすめ):プロジェクトフォルダ内の
.claude/settings.json - ユーザー全体:
~/.claude/settings.json(すべてのプロジェクトに適用される)
この記事ではプロジェクト単位の設定を基本に進めます。
ここまで揃っていれば、あとはsettings.jsonに数行書くだけです。
Step 1:settings.jsonにHooks設定を書く
プロジェクトフォルダの.claude/settings.jsonを開きます。ファイルがなければ新規作成してください。
Hooksの設定は、hooksブロックの中に書きます。基本構造は次のようになります。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "実行したいコマンド"
}
]
}
]
}
}
各フィールドの意味を確認します。
matcher:どのツール操作後にフックするかを正規表現パターンで指定。パイプ区切りで複数のツール名を指定できますhooks:matcherに一致した時に実行するフックの配列type:"command"を指定(シェルコマンドを実行するタイプ)shell:"powershell"を指定(Windows環境でPowerShellコマンドを実行する場合に推奨)command:実際に実行するコマンドを文字列で指定
※Claude Codeのバージョンによって設定のJSON構造が変わる可能性があります。動かない場合は公式ドキュメント(code.claude.com/docs/en/hooks)で最新の構造を確認してください
stdinでJSON入力を受け取れるので、そこからfile_pathを抽出してコマンドに渡します。PowerShellの場合は次のように書きます。
Prettierでフォーマットを自動実行する例:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "$null, $json = $input; $file = ($json | ConvertFrom-Json).tool_input.file_path; if ($file -match '\.(js|ts|jsx|tsx|css|json|md)$') { npx prettier --write $file }"
}
]
}
]
}
}
ESLintでlintを自動実行する例:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "$null, $json = $input; $file = ($json | ConvertFrom-Json).tool_input.file_path; if ($file -match '\.(js|ts|jsx|tsx)$') { npx eslint $file }"
}
]
}
]
}
}
pytestでtestを自動実行する例:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "$null, $json = $input; $file = ($json | ConvertFrom-Json).tool_input.file_path; if ($file -match '\.py$') { pytest --tb=short }"
}
]
}
]
}
}
pytestの場合、ファイルパスを直接渡すよりpytest全体を走らせる方が安定します。テストファイルの変更だけでなく、ソースコード側の変更でもテスト全体が回るので漏れがなくなります。
複数のhookを同時に設定したい場合は、同じmatcherのhooks配列にコマンドを追加します。Prettier→ESLintのように実行順序を保証したい場合は、別々のhookに分けず、1つのcommand内で順番に実行します。処理が長くなる場合は、PowerShellスクリプトファイルにまとめて、そのスクリプトをhookから呼び出す方法が安全です。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "$null, $json = $input; $file = ($json | ConvertFrom-Json).tool_input.file_path; if ($file -match '\.(js|ts)$') { npx prettier --write $file 2>$null; npx eslint $file 2>$null }"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "$null, $json = $input; $file = ($json | ConvertFrom-Json).tool_input.file_path; if ($file -match '\.py$') { pytest --tb=short 2>$null }"
}
]
}
]
}
}
すでにsettings.jsonが存在する場合は、既存の設定を残したまま"hooks"キーを追記してください。
実務的な観点で言うと、この設定のメリットは次の2点に集約されます。
- Pushしてからエラーに気づくより、Claude Codeが編集した直後にtestが走る方が早い——CIが落ちる前に手元で問題に気付ける
- PRのdiffがフォーマット差分で埋まらない——レビュー前の自動整形で、実質的な変更だけが残る
導入するとすぐ実感できる違いです。
Step 2:設定を反映したか確認する
設定を書いただけでは、本当に反映されているか分かりません。Claude Codeの画面で確認します。
- Claude Codeを開いているターミナルで、プロンプトに
/hooksと入力してEnter - 設定済みのhooks一覧が表示されるので、先ほど書いた内容が含まれているか確認
期待される表示例:PostToolUseイベントに対して、登録したコマンドとmatcher: Edit|Writeが一覧に並びます。
表示されない場合の簡易チェック:
settings.jsonのJSON構造にエラーがないか確認(カンマの過不足、括弧の対応)- ファイルパスが正しいか確認(
.claude/settings.jsonに配置されているか)
JSONの構文チェックはPowerShellでもできます。
Get-Content .claude/settings.json | ConvertFrom-Json
エラーが出なければ構文は正しい状態です。
設定は認識されました。ここからは実際にファイルを編集して、hookが走るか試します。
Step 3:実際にファイルを編集して発火を試す
設定が反映されていることを確認したら、実際にファイルを編集してhookが動くかテストします。
- プロジェクト内の任意のファイルをClaude Codeに編集させる(
EditまたはWriteが使われる指示を出す) - 編集直後に、コマンド出力が表示されるか確認する
- Prettierなら「ファイルが整形された」旨の出力、ESLintならlint結果、pytestならテスト結果が表示されれば成功
期待される結果の例:
file.ts 23ms (unchanged)
上記はPrettierが走った時の例です。「unchanged」は既に整形済みであることを示しています。
発火が確認できたら設定完了です。
うまくいかない時は
Step 3でhookが発火しなかった場合、以下の原因候補を上から順に確認してください。
1. JSON validation failedエラーが出る場合
settings.jsonの構文エラーが最も多い原因です。
- カンマ忘れ:配列の要素間やオブジェクトの最後の要素に余計なカンマがないか
- エスケープ不足:
commandフィールド内のダブルクォートが\"とエスケープされているか - 括弧の対応:
{と}、[と]が正しくペアになっているか
JSONのバリデータ(エディタの拡張機能やオンラインツール)に通すと一発で見つかります。
2. hookが発火しない(エラーも出ない)場合
- matcherの書き方:
"Edit|Write"が正しく書かれているか。大文字小文字も区別されます - commandのパス解決:
npxやpythonがPowerShellで認識されているか。ターミナルでnpx --versionやpython --versionを実行して確認 - stdinのJSON構造:
ConvertFrom-Jsonでエラーが出ていないか。デバッグ用に一時的にコマンドを変更して中身を確認する方法もあります
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "$null, $json = $input; $json | Out-File -FilePath ./hook_debug.log"
}
]
}
hook_debug.logにstdinの中身が書き出されるので、JSONの構造を確認できます。
3. PowerShellとbashの違いによるエラー
海外の記事でよく見るbash前提のコマンド(jqやxargsを使う書き方)は、Windows PowerShellではそのまま動きません。
| 項目 | bash | PowerShell |
|---|---|---|
| stdinの読み取り | `cat`や`<&0` | `$input` |
| JSONのパース | `jq` | `ConvertFrom-Json` |
| 変数の代入 | `VAR=$(…)` | `$VAR = …` |
| パス区切り | `/` | `\`(PowerShell内では`/`も動くことが多い) |
jqがインストールされていなくても、PowerShellのConvertFrom-Jsonで同等の処理ができます。
4. 複数のhookをまとめるか、別々に定義するか
- 1つのcommandにまとめる:
&&や;で繋いで書く。シンプルだがエラー時の切り分けが難しい - 別々のmatcherグループに分ける(この記事の例):
PostToolUse配列に別々のmatcherオブジェクトを並べる。エラー箇所が特定しやすく、ON/OFFも個別にできる
順序が不要なものは別々に定義してもよい。順序が必要なもの(Prettier→ESLintなど)は1つのcommandにまとめるか、PowerShellスクリプトファイルに外出ししてください。
設定が終わったら——何が変わるか
ここまでの設定で、以下のチェックリストがすべて埋まっていれば完了です。
settings.jsonにhooks設定を書いた/hooksで設定が反映されていることを確認した- 実際にファイルを編集してhookが発火した
運用上、次のような変化があります。
- 使っているツールに合わせてmatcherを変えれば、自分専用の自動化が組み立てられる(例:
"Edit"だけに絞れば手動書き込みは対象外) - Claude Codeがファイルを編集するたびに手動でコマンドを叩く必要がなくなる
PostToolUse以外にもPreToolUseがあれば、ファイル編集前にもフックをかけられる
次にやることの目安:
- 読む:Claude Codeのhooksに関するドキュメントで、他のイベントタイプ(
PreToolUse、Notificationなど)を確認する。ついでにスキル機能で繰り返し作業を自動化する方法も併読すると、HooksとSkillsの使い分けが見えてくる - 試す:今のプロジェクトでhooks設定を少し変えてみる(matcherの条件変更、コマンドの追加など)
- 高度な設定:複数プロジェクトで共通のhooksを使いたい場合は、CLAUDE.mdをWindowsで作成する手順も参考に、ユーザー全体の
~/.claude/settings.jsonへの記載を検討する
まとめ
Hooksの設定はsettings.jsonに数行書くだけで完了します。Claude Codeがファイルを編集するたびにターミナルを切り替えていた一手間はゼロにできます。Windows環境でもPowerShellのConvertFrom-Jsonを使えばjqなしで動くので、コピペで始められます。設定後は/hooksで確認→実際にファイル編集して発火をテスト、の流れでそのまま運用に乗ります。
