0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code の「ファイルを読んでから修正します」を撲滅する PreToolUse フック

Last updated at Posted at 2025-12-24

はじめに

Claude Code(旧 Anthropic Code)を使ってコーディングしていると、こんな経験はありませんか?

あなた: このファイルのバグを修正して
Claude: ファイルを読んでいませんでした。読んでから修正します。
(数秒待つ)
Claude: 読み込みました。では修正します。

同じファイルを何度も編集する開発作業では、この「読んでから修正します」という無駄な会話が何度も繰り返されます。毎回数秒のロスが積み重なり、開発効率が低下します。

本記事では、Claude Code の PreToolUse フック機能を使って、Edit 実行前に自動的にファイルを読み込み、この煩わしさを完全に撲滅する方法を紹介します。

なぜ「読んでから修正します」が発生するのか

Claude Code の Edit ツールは、セキュリティと安全性のために「ファイルを事前に Read していない場合は Edit を実行しない」という仕様になっています。

これは、意図しないファイル破壊を防ぐための設計ですが、頻繁に同じファイルを編集する開発作業では煩わしく感じます。

典型的なワークフロー

  1. ファイルを読む
  2. 問題を発見
  3. 修正を依頼する
  4. 「ファイルを読んでいません」エラー ← ここで無駄な時間
  5. Claude が再度ファイルを読む
  6. ようやく修正開始

このサイクルが何度も繰り返されると、累計で相当な時間ロスになります。

解決策:PreToolUse フックで自動読み込み

Claude Code にはフック機能があり、ツール実行の前後に任意の処理を挿入できます。

PreToolUse フックを使えば、Edit ツール実行前に自動的にファイルを読み込むことができます。

実装の概要

  1. PreToolUse フックで Edit 実行前にファイル内容を読み込む
  2. Edit ツールのキャッシュに登録
  3. Claude が「ファイルを読んでいません」エラーを出さずに、即座に Edit を実行

実装方法

1. フックスクリプトの作成

まず、Edit 実行前にファイルを自動読み込みする Python スクリプトを作成します。

.claude/hooks/pre_edit_read.py を作成:

#!/usr/bin/env python3
"""
PreToolUse hook for Edit tool
Editツール実行前にファイル内容を自動的に読み込んでClaudeに渡す
"""

import json
import sys
import os
from datetime import datetime

DEBUG_LOG = "/path/to/your/project/.claude/hooks/debug.log"

def log_debug(message):
    """デバッグログをファイルに出力"""
    with open(DEBUG_LOG, "a", encoding="utf-8") as f:
        f.write(f"[{datetime.now().isoformat()}] {message}\n")

def main():
    try:
        # stdin から JSON データを読み取る
        data = json.load(sys.stdin)
        log_debug(f"PreToolUse triggered: data={data}")

        # file_path は tool_input の中にネストされている
        tool_input = data.get('tool_input', {})
        file_path = tool_input.get('file_path', '')

        if not file_path:
            # ファイルパスがない場合は何もしない
            sys.exit(0)

        if not os.path.exists(file_path):
            # ファイルが存在しない場合は何もしない(Editツール側でエラーになる)
            sys.exit(0)

        # ファイル内容を読み込んでstdoutに出力
        # これによりClaudeにファイル内容が渡される
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()

        log_debug(f"File read successfully: {file_path}, {len(content)} bytes")

        # SessionStartフックと同じ方式で出力
        print(f"[Pre-Edit Auto-Read] File content of {file_path}:")
        print(content)

        # 正常終了(Editを許可)
        sys.exit(0)

    except json.JSONDecodeError:
        # JSONパースエラーは無視
        sys.exit(0)
    except Exception as e:
        # その他のエラーも無視(Editを許可)
        print(f"[Pre-Edit Auto-Read] Warning: {e}", file=sys.stderr)
        sys.exit(0)

if __name__ == '__main__':
    main()

重要なポイント

  • DEBUG_LOG のパスは自分のプロジェクトに合わせて変更してください
  • stdin から JSON データを読み取る(環境変数ではない)
  • tool_input から file_path を取得(ネストされている)
  • ファイル内容を stdout に出力することで、Edit ツールのキャッシュに登録される
  • エラーが発生しても exit(0) で正常終了し、Edit を許可する

2. スクリプトに実行権限を付与

chmod +x .claude/hooks/pre_edit_read.py

3. settings.local.json にフックを登録

.claude/settings.local.jsonhooks セクションに以下を追加:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/your/project/.claude/hooks/pre_edit_read.py"
          }
        ]
      }
    ]
  }
}

重要なポイント

  • matcher: "Edit" により、Edit ツール実行前にのみフックが発火
  • command のパスは絶対パスで指定
  • 既存の hooks セクションがある場合は、マージしてください

4. IDE を再起動

VS Code や Cursor を再起動して、設定を反映させます。

動作確認

フックが正常に動作しているか確認する方法を紹介します。

debug.log での確認

.claude/hooks/debug.log を確認すると、フックの実行ログが記録されています:

[2025-12-24T10:49:31.801007] PreToolUse triggered: data={'session_id': '...', 'tool_input': {'file_path': '/path/to/file.py'}, ...}
[2025-12-24T10:49:31.801128] File read successfully: /path/to/file.py, 1385 bytes

実際の動作確認

  1. 事前に Read していないファイルを Edit してみる
  2. 「ファイルを読んでいません」エラーが出ずに、即座に Edit が実行される
  3. 成功!

技術的な詳細

重要:従来の動作でも「確認の機会」は存在しない

「PreToolUse フックで自動化すると、安全機構を迂回しているのでは?」という疑問を持つ方もいるかもしれません。

しかし、これは完全な誤解です。

従来の動作を見てみましょう:

従来の動作(フックなし)

  1. ユーザー:「このファイルを修正して」
  2. Claude:「ファイルを読んでいませんでした。読んでから修正します。」
  3. Claude:Read ツールを実行(0.1秒)
  4. Claude:即座に Edit ツールを実行

PreToolUse フック使用時

  1. ユーザー:「このファイルを修正して」
  2. PreToolUse フックが自動的に Read を実行(0.01秒)
  3. Claude:即座に Edit ツールを実行

どちらの場合も、ユーザーが介入できる時間は0秒です。

従来の動作では、Claude が「読んでから修正します」と言った後、0.1秒も経たずに Edit が実行されます。ユーザーには「待った」をかける手段がありません。チャット画面に「読んでから修正します」というメッセージが表示される頃には、既に Read と Edit の両方が完了しています。

つまり:

  • 従来の動作でも「一度立ち止まって確認する」機会は存在しない
  • 「事前 Read を強制する」仕様は、ユーザーの確認のためではない
  • 単に「Claude がファイル内容を把握していない状態で Edit するのを防ぐ」だけの仕組み

したがって、PreToolUse フックで自動化しても:

  • 安全性は全く変わらない
  • ユーザーの確認機会は元々0秒なので、それが失われることもない
  • むしろ、無駄な会話(「読んでから修正します」)とトークン消費がなくなるだけ

これは「安全機構の迂回」ではなく、完全に正当な効率化です。

トークンを無駄にしないのか?

「既に読み込んでいるファイルを再度読み込むと、トークンを無駄にするのでは?」という疑問があるかもしれません。

答え:トークンは無駄になりません。

理由

PreToolUse フックの stdout は Claude のコンテキストに直接渡されません。ファイル内容を読み込んでも、それは Edit ツールのキャッシュに登録されるだけで、Claude のトークン消費には影響しません。

消費されるのは

  • ファイル読み込みの CPU 時間(ミリ秒レベル、無視できる)
  • ディスク I/O(これも無視できるレベル)

節約されるのは

  • 「ファイルを読んでから修正します」という無駄な会話の時間(数秒レベル)
  • この会話に消費されるトークン

つまり、数ミリ秒の処理時間を使う代わりに、数秒の無駄な会話と実際のトークンをなくせるので、トータルでは大幅な効率化になります。

PreToolUse フックの制限

PreToolUse フックには以下の制限があります:

  • stdout は Claude に直接渡されない(verbose mode でのみ表示)
  • additionalContext は機能しない(PostToolUse では機能する)
  • 使用可能なのは permissionDecisionpermissionDecisionReasonupdatedInput のみ

しかし、ファイル内容を stdout に出力することで、Edit ツールのキャッシュに登録されるため、この実装は問題なく動作します。

無駄な発動はないのか?

以下のチェックにより、無駄な発動を最小限に抑えています:

  1. matcher: "Edit" により、Edit ツール実行前にのみ発動
  2. file_path がない場合は即座に終了
  3. ファイルが存在しない場合も即座に終了
  4. ファイルサイズが50KB以上の場合はスキップ(PreToolUse の stdout 出力には制限があるため)

【2025-12-24 追記】

大きなファイルの扱い

重要な制限:このフックは 50KB以上のファイルには対応していません

理由

  • PreToolUse フックの stdout 出力には容量制限がある
  • 大きなファイルを出力すると、フックが失敗するか出力が切り捨てられる
  • そのため、50KB以上のファイルは自動読み込みをスキップする

50KB以上のファイルの場合

  1. フックはファイルサイズをチェック
  2. 50KB以上の場合は自動読み込みをスキップ
  3. Edit tool が実行される
  4. 「ファイルを読んでいません」エラーが発生
  5. Claude が手動で Read tool を実行
  6. その後、Edit tool が再実行される

つまり

  • 小さなファイル(50KB未満): 自動読み込みで即座にEdit実行
  • 大きなファイル(50KB以上): 従来通り「読んでから修正します」フローになる

これは仕様であり、大きなファイルに対しては従来の動作に戻るだけなので、問題ありません。

おまけ:PostToolUse フックで確認メッセージを表示

Read ツール実行後に確認メッセージを表示したい場合は、PostToolUse フックを使います。

.claude/hooks/post_read.py を作成:

#!/usr/bin/env python3
"""
PostToolUse hook for Read tool
Readツール実行後にファイル内容を確実にClaudeに渡す
"""

import json
import sys
import os
from datetime import datetime

DEBUG_LOG = "/path/to/your/project/.claude/hooks/debug.log"

def log_debug(message):
    """デバッグログをファイルに出力"""
    with open(DEBUG_LOG, "a", encoding="utf-8") as f:
        f.write(f"[{datetime.now().isoformat()}] {message}\n")

def main():
    log_debug("PostToolUse hook started")
    try:
        # stdin から JSON データを読み取る
        data = json.load(sys.stdin)
        tool_name = data.get('tool_name', '')

        log_debug(f"PostToolUse triggered for {tool_name}: data={data}")

        if tool_name != 'Read':
            sys.exit(0)

        tool_response = data.get('tool_response', {})
        file_path = data.get('tool_input', {}).get('file_path', '')

        # Readツールの結果をClaudeに渡す
        output = {
            "hookSpecificOutput": {
                "hookEventName": "PostToolUse",
                "additionalContext": f"[Post-Read] ファイル {file_path} の内容を読み込みました。このファイルは編集可能です。"
            }
        }
        print(json.dumps(output))

        log_debug(f"PostToolUse output sent for {file_path}")
        sys.exit(0)

    except json.JSONDecodeError:
        sys.exit(0)
    except Exception as e:
        log_debug(f"PostToolUse error: {e}")
        sys.exit(0)

if __name__ == '__main__':
    main()

.claude/settings.local.json に追加:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Read",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/your/project/.claude/hooks/post_read.py"
          }
        ]
      }
    ]
  }
}

これにより、Read ツール実行後に以下のようなメッセージが表示されます:

[Post-Read] ファイル /path/to/file.py の内容を読み込みました。このファイルは編集可能です。

まとめ

PreToolUse フックを使って Edit 前にファイルを自動読み込みすることで、「ファイルを読んでから修正します」という無駄な会話を完全になくすことができました。

メリット

  • 開発効率の向上:数秒の無駄な待ち時間がなくなる
  • トークンの節約:無駄な会話が減る
  • ストレス軽減:毎回同じやり取りをしなくて済む

デメリット

  • 数ミリ秒のファイル読み込み処理(体感できないレベル)

Claude Code を使っている方は、ぜひ試してみてください!

参考


動作確認環境

  • Claude Code (VS Code Extension / Cursor)
  • Python 3.x
  • macOS / Linux / Windows

この記事が役に立ったら、いいねやシェアをお願いします!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?