Claude Code の編集後に lint と format を走らせる:PostToolUse と Edit|Write|MultiEdit

Claude Code 公開: 更新:

PostToolUse フックに matcher "Edit|Write|MultiEdit" を書くと、編集のたびに Prettier や ESLint、ruff を実行できます。stdin の tool_input.file_path から対象ファイルを取り出す方法と、失敗を Claude に返す方法を解説します。

検証日 2026年9月30日 仕様変更が早い分野です。最新の公式ドキュメントも併せてご確認ください。 記事の作り方と検証手順
目次
  1. hooks の仕組み
  2. 設定例:編集後に Prettier と ESLint を実行する
  3. Python プロジェクトの場合(ruff)
  4. 動作確認
  5. 運用上の注意
  6. 発展:PreToolUse で危険なコマンドを止める
  7. まとめ

「フォーマットを揃えてからコミットして」と CLAUDE.md に書いても、Claude が実行を忘れることがあります。指示は確率的に守られるものだからです。この問題を確実に解決するのが hooks です。hooks は Claude の判断を介さず、Claude Code 本体が決められたタイミングでシェルコマンドを実行する仕組みです。

この記事では、Claude がファイルを編集するたびに Prettier や ESLint、Python なら ruff を自動実行し、失敗したら Claude 自身に修正させる設定を作ります。

KEY POINT

この記事で分かること

  • hooks のイベント種類と設定ファイルの書き方
  • 編集されたファイルだけを対象に lint / format を走らせる方法
  • lint 失敗を Claude にフィードバックして自動修正させる方法

hooks の仕組み

hooks は settings.json の hooks キーに書きます。イベントごとに「どのツールに反応するか(matcher)」と「実行するコマンド」を指定します。

イベント発火タイミング主な用途
PreToolUseツール実行前危険なコマンドのブロック、事前チェック
PostToolUseツール実行後lint / format の自動実行、テスト
UserPromptSubmitユーザーが指示を送信したとき指示への情報付加、検証
NotificationClaude が確認や通知を出すときデスクトップ通知、Slack 連携
StopClaude が応答を終えたとき最終チェック、完了通知
SubagentStopサブエージェントが終了したときサブエージェントの成果物検証
SessionStartセッション開始時環境変数の読み込み、コンテキストの注入
PreCompactコンテキスト圧縮の直前重要情報の退避

hook コマンドには、標準入力(stdin)で JSON が渡されます。PostToolUse の場合、tool_name と tool_input(編集なら file_path を含む)が入っています。

設定例:編集後に Prettier と ESLint を実行する

.claude/settings.json に次のように書きます。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/format.sh"
          }
        ]
      }
    ]
  }
}

matcher はツール名に対する正規表現です。ファイルを変更するツールは Edit、Write、MultiEdit なので、この 3 つを | でつなぎます。

次に、.claude/hooks/format.sh を作ります。stdin の JSON から編集されたファイルのパスを取り出し、対象のファイルだけをフォーマットします。

#!/usr/bin/env bash
set -euo pipefail

# stdin の JSON から file_path を取り出す(jq が必要)
file=$(jq -r '.tool_input.file_path // empty')
[ -z "$file" ] && exit 0
[ -f "$file" ] || exit 0

case "$file" in
  *.ts|*.tsx|*.js|*.jsx|*.json|*.css|*.md)
    npx prettier --write "$file" >/dev/null
    ;;
esac

case "$file" in
  *.ts|*.tsx|*.js|*.jsx)
    if ! npx eslint "$file"; then
      echo "ESLint がエラーを報告しました。上記の指摘を修正してください: $file" >&2
      exit 2
    fi
    ;;
esac
exit 0
chmod +x .claude/hooks/format.sh

用語解説

終了コードの意味: 0 は成功。2 は「ブロック」で、標準エラー出力の内容が Claude に渡され、Claude は指摘に従って修正を試みます。それ以外の終了コードは処理を止めずにユーザーへ警告を表示します。

Python プロジェクトの場合(ruff)

#!/usr/bin/env bash
set -euo pipefail
file=$(jq -r '.tool_input.file_path // empty')
[[ "$file" == *.py ]] || exit 0
[ -f "$file" ] || exit 0

ruff format "$file" >/dev/null
if ! ruff check "$file"; then
  echo "ruff の指摘を修正してください: $file" >&2
  exit 2
fi

ruff check --fix を使えば自動修正できる項目は hook 側で直せます。その場合、残ったエラーだけが Claude に渡ります。

動作確認

  1. /hooks コマンドで登録された hook が表示されることを確認します。
  2. Claude に「src/example.ts にわざとフォーマットの崩れた関数を追加して」と指示します。
  3. 編集直後に Prettier が走り、ファイルが整形されていれば成功です。
  4. ESLint エラーになるコード(未使用変数など)を書かせ、Claude が指摘を受けて修正するか確認します。

hook の実行ログは、Claude Code を claude --debug で起動すると詳細が見られます。

運用上の注意

hook は毎回実行される

PostToolUse は編集のたびに走ります。プロジェクト全体の lint(eslint .)を書くと、1 回の編集ごとに数十秒かかることがあります。必ず「編集されたファイルだけ」を対象にしてください。

  • hook 内で Claude の編集を上書きする場合は慎重に: フォーマッタは安全ですが、コード生成やファイル移動を hook で行うと Claude の認識とファイルの実体がずれます。
  • jq のインストールが必要: macOS は brew install jq、Ubuntu は apt install jq。jq を避けたい場合は Python でパースする方法もあります。
  • チームで共有する場合: hook スクリプトはリポジトリに入れ、settings.json(共有)から相対パスで呼びます。個人環境だけの hook は settings.local.json に書きます。

発展:PreToolUse で危険なコマンドを止める

同じ仕組みで、実行前に危険なコマンドを検査できます。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/guard.sh"
          }
        ]
      }
    ]
  }
}
#!/usr/bin/env bash
cmd=$(jq -r '.tool_input.command // empty')
if echo "$cmd" | grep -Eq 'rm -rf /|git push --force|DROP TABLE'; then
  echo "このコマンドは hooks により禁止されています: $cmd" >&2
  exit 2
fi
exit 0

permissions の deny と組み合わせると二重の保護になります。deny の書き方は settings.json で permissions を設計する を参照してください。

まとめ

  • hooks は Claude の判断を介さず確実に実行されるため、lint / format の自動化に向いている
  • PostToolUse + matcher: "Edit|Write|MultiEdit" で編集後に走らせる
  • stdin の JSON から tool_input.file_path を取り出し、編集されたファイルだけを対象にする
  • 終了コード 2 と標準エラー出力で、Claude に修正を促せる

よくある質問

hooks は Claude が勝手に無視することはありますか?
ありません。hooks は Claude の判断ではなく Claude Code 本体が決定的に実行するため、指示の聞き漏らしが起きません。
hooks が失敗したら Claude に伝わりますか?
終了コード 2 で終了すると、標準エラー出力の内容が Claude にフィードバックされ、修正を試みます。終了コード 0 なら成功、それ以外はユーザーへの警告として表示されます。
hooks の設定はどこに書きますか?
settings.json の hooks キーです。ユーザー・プロジェクト・ローカルの各スコープに書けます。/hooks コマンドから対話的に追加することもできます。

読者からの質問と回答

Q. hooks を settings.json に書いたのに実行されません。何を確認すればよいですか?

編集部の回答検索でよく調べられている質問

次の順で確認してください。

  1. /hooks を実行し、登録した hook が一覧に出るか見る。出なければ JSON の構文(末尾カンマ、引用符)か、置き場所(.claude/settings.json か ~/.claude/settings.json)が原因です
  2. matcher はツール名の正規表現です。ファイル編集に反応させるなら Edit|Write|MultiEdit、コマンドなら Bash です。イベント名(PreToolUse / PostToolUse)の綴りも確認します
  3. スクリプトに実行権限があるか(chmod +x)、シェバン行があるか、jq が入っているかを確認します。bash .claude/hooks/format.sh のように bash 経由で呼べば実行権限は不要です
  4. claude --debug で起動すると、hook の実行と終了コード、標準エラー出力が表示されます

設定を編集したあとはセッションを再起動すると確実に反映されます。

参考にした一次情報

この記事は公式ドキュメントを基に AI が下書きを作成し、運営者が内容を確認して公開しています。誤りを見つけた場合は お問い合わせからお知らせください。