はじめに
Claude Code(旧 Anthropic Code)を使ってコーディングしていると、こんな経験はありませんか?
あなた: このファイルのバグを修正して
Claude: ファイルを読んでいませんでした。読んでから修正します。
(数秒待つ)
Claude: 読み込みました。では修正します。
同じファイルを何度も編集する開発作業では、この「読んでから修正します」という無駄な会話が何度も繰り返されます。毎回数秒のロスが積み重なり、開発効率が低下します。
本記事では、Claude Code の PreToolUse フック機能を使って、Edit 実行前に自動的にファイルを読み込み、この煩わしさを完全に撲滅する方法を紹介します。
なぜ「読んでから修正します」が発生するのか
Claude Code の Edit ツールは、セキュリティと安全性のために「ファイルを事前に Read していない場合は Edit を実行しない」という仕様になっています。
これは、意図しないファイル破壊を防ぐための設計ですが、頻繁に同じファイルを編集する開発作業では煩わしく感じます。
典型的なワークフロー
- ファイルを読む
- 問題を発見
- 修正を依頼する
- 「ファイルを読んでいません」エラー ← ここで無駄な時間
- Claude が再度ファイルを読む
- ようやく修正開始
このサイクルが何度も繰り返されると、累計で相当な時間ロスになります。
解決策:PreToolUse フックで自動読み込み
Claude Code にはフック機能があり、ツール実行の前後に任意の処理を挿入できます。
PreToolUse フックを使えば、Edit ツール実行前に自動的にファイルを読み込むことができます。
実装の概要
- PreToolUse フックで Edit 実行前にファイル内容を読み込む
- Edit ツールのキャッシュに登録
- 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.json の hooks セクションに以下を追加:
{
"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
実際の動作確認
- 事前に Read していないファイルを Edit してみる
- 「ファイルを読んでいません」エラーが出ずに、即座に Edit が実行される
- 成功!
技術的な詳細
重要:従来の動作でも「確認の機会」は存在しない
「PreToolUse フックで自動化すると、安全機構を迂回しているのでは?」という疑問を持つ方もいるかもしれません。
しかし、これは完全な誤解です。
従来の動作を見てみましょう:
従来の動作(フックなし):
- ユーザー:「このファイルを修正して」
- Claude:「ファイルを読んでいませんでした。読んでから修正します。」
- Claude:Read ツールを実行(0.1秒)
- Claude:即座に Edit ツールを実行
PreToolUse フック使用時:
- ユーザー:「このファイルを修正して」
- PreToolUse フックが自動的に Read を実行(0.01秒)
- 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 では機能する) - 使用可能なのは
permissionDecision、permissionDecisionReason、updatedInputのみ
しかし、ファイル内容を stdout に出力することで、Edit ツールのキャッシュに登録されるため、この実装は問題なく動作します。
無駄な発動はないのか?
以下のチェックにより、無駄な発動を最小限に抑えています:
-
matcher: "Edit"により、Edit ツール実行前にのみ発動 file_pathがない場合は即座に終了- ファイルが存在しない場合も即座に終了
- ファイルサイズが50KB以上の場合はスキップ(PreToolUse の stdout 出力には制限があるため)
【2025-12-24 追記】
大きなファイルの扱い
重要な制限:このフックは 50KB以上のファイルには対応していません。
理由:
- PreToolUse フックの stdout 出力には容量制限がある
- 大きなファイルを出力すると、フックが失敗するか出力が切り捨てられる
- そのため、50KB以上のファイルは自動読み込みをスキップする
50KB以上のファイルの場合:
- フックはファイルサイズをチェック
- 50KB以上の場合は自動読み込みをスキップ
- Edit tool が実行される
- 「ファイルを読んでいません」エラーが発生
- Claude が手動で Read tool を実行
- その後、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
この記事が役に立ったら、いいねやシェアをお願いします!