Claude Codeフックでタイムスタンプ注入
Claude Codeの1Mコンテキストで長時間セッションを走らせていると、会話のどのあたりが何時頃の話だったか見失う。「PreToolUseフックにdateコマンドを仕込めば、あらゆるツール実行時にタイムスタンプが残る」というTipsを見かけて試したが、思った通りには動かなかった。フックの仕様を理解してUserPromptSubmitに切り替えるまでの記録。
きっかけ
1Mコンテキストのセッションは数時間に及ぶことがある。途中で「さっきのエラー、何時頃だっけ」と遡りたくなっても、会話ログに時刻情報がない。claude-code-syncのDiscordで「PreToolUseフックにdateを入れると便利」というTipsが流れてきて、settings.local.jsonを開いた。
試行1: PreToolUseフックにdateコマンドを追加
PreToolUseフックでBashツール実行前にdateコマンドを走らせれば、コンテキストにタイムスタンプが入るはず。そのまま書いた。
.claude/settings.local.json のhooksセクションに追加:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "date"
}
]
}
]
}
}
結果: 何も起きない。タイムスタンプがコンテキストに現れない。
試行2: Windows環境のdateコマンド問題
Git Bash環境なのでLinuxのdateが使えるはず――と思ったが、フックの実行環境ではWindows版のdateが呼ばれている可能性を疑った。bash -c "date"でラップしてみた。
{
"type": "command",
"command": "bash -c \"date\""
}
結果: これも動かない。タイムスタンプは表示されなかった。
仕様の壁: PreToolUseのstdoutはコンテキストに入らない
ここで手を止めて仕様を調べた。判明した事実:
- PreToolUseフックのstdoutは、Claudeのコンテキストに注入されない
- フックの出力は
Ctrl+Oで開く詳細モードのUIにのみ表示される - つまりデバッグ用の表示であって、Claudeが「読める」情報にはならない
PreToolUseフックは「ツール実行を許可/拒否する」ためのゲートキーパーであって、コンテキストに情報を追加する仕組みではなかった。
試行3: UserPromptSubmitフックに変更
フックの種類を見直した。UserPromptSubmitフックは、ユーザーがメッセージを送信したタイミングで実行され、そのstdoutがsystem-reminderとしてコンテキストに注入される。
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "bash -c \"date '+%Y-%m-%d %H:%M:%S'\""
}
]
}
]
}
}
結果: 成功。メッセージを送信するたびに、system-reminderとしてタイムスタンプがコンテキストに入るようになった。
最終的な設定
UserPromptSubmitフックには、既存のVOICEVOX音声再生フックと並べてdate hookを配置した。
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "powershell -WindowStyle Hidden -File C:/scripts/play-sound.ps1"
},
{
"type": "command",
"command": "bash -c \"date '+%Y-%m-%d %H:%M:%S'\""
}
]
}
]
}
}
メッセージ送信のたびに:
- 音声が再生される(応答開始の通知)
- タイムスタンプがsystem-reminderとしてコンテキストに入る
確認方法
動作しているかは、Claudeに「現在のsystem-reminderの内容を教えて」と聞くか、会話ログの中にタイムスタンプ付きのsystem-reminderが挟まっているかで確認できる。
学び
- PreToolUseフック: ツール実行の許可/拒否が目的。stdoutはUI表示のみでコンテキストには入らない
- UserPromptSubmitフック: ユーザー入力時に実行され、stdoutがsystem-reminderとしてコンテキストに注入される
- フックの種類によってstdoutの扱いが違う。「出力がどこに流れるか」を把握してからフックを選ぶ必要がある
- 1Mコンテキストの長時間セッションで、タイムスタンプが入った途端に「あのエラーは14時頃だった」とスクロールして探し当てられるようになった