Claude Codeの日付ミスをHookで機械的に防いだ話


ある日、Claude Codeに「今日は何日?」と聞いたら、間違った答えが返ってきました。

原因を辿ると、直前に公開した記事のpubDate(公開日)をそのまま「今日」だと勘違いしていたことが分かりました。記事の日付が間違っていたから、今日の日付も間違えて答えた、という循環的なミスです。

「CLAUDE.mdに『日付はシステム提供のcurrentDateを見ろ』って書いてあるのに、なんで守られてないの?」と聞いたら、Claudeから返ってきたのは「保証はできない。文書に書くだけでは、次も同じミスが起きる可能性がある」という答えでした。

だったら文書じゃなくて、機械的に強制する仕組みを作ろう。そう思って、記事の日付ミスをブロックするHookを作った話をまとめます。

「今日は何日?」で変な答えが返ってきた

このブログでは、記事を公開するたびにpubDateというフィールドに公開日を書いています。

pubDate: '2026-07-04T20:00:00'

前日にこの記事を公開したばかりの状態で「今日は何日?」と聞いたところ、Claude Codeは記事に書いたpubDateを見て「今日は7/3」と答えました。実際は7/4でした。

よく考えると当たり前の話で、記事のpubDateはあくまで「その記事を公開した日」であって、「今日の日付」の保証にはなりません。それなのに、直近の作業内容から逆算して答えてしまいました。しかも記事のpubDate自体、Claudeが1日ズレて書いてしまっていたので、間違いの上に間違いを重ねる形になっていました。

CLAUDE.mdに書いても守られる保証はあるのか

このミスを指摘したとき、ふと気になって聞いてみました。

CLAUDE.mdに書いたことが全然守られてないけど、次も守られないんじゃないの。ちゃんと守られる保証はあるの?

全プロジェクト共通で読み込まれるグローバルのCLAUDE.md(~/.claude/CLAUDE.md)には、以前から「日付はシステムが提供するcurrentDateを最優先で参照する」と書いてあります。それなのに守られなかった。

Claudeから返ってきた答えは「保証はない。CLAUDE.mdはあくまで指示書であって、読み落としや思い込みが起きる可能性は残る」という説明でした。

さらに自分でも調べてみると、CLAUDE.mdは「毎回読んでもらう前提のお願い」でしかなく、コンテキスト(会話履歴や指示の分量)が多くなると後半の内容ほど忘れられやすいこともあるとのこと。同じミスを繰り返さないよう確実な仕組みを作るなら、文書ではなくHookが必要だということが分かりました。

ということで、Hookで日付ミスを防ぐことにしました。

💡 Hookの基本的な仕組み(settings.jsonへの設定方法、デスクトップ版特有の注意点)はこちらの記事exit codestderrがなぜClaudeに伝わるのかはこちらの記事で詳しく解説しています。

最初のアイデアには穴があった

最初にClaudeに提案されたHookのルールはこんな感じでした。

記事ファイルの pubDate が「今日の日付」と一致してるかチェックする

これで新規記事の日付ミスは防げそうです。でも、ふと引っかかって、Claude Codeにこう聞いてみました。

でもそれだとpubDateだけでしょ?修正した場合もpubDateが今日の日付になっちゃうんじゃないの?修正した場合は更新日付を直したいんだっけ?

たしかにその通りでした。このブログのルールでは、pubDateは「初出公開日」で修正時に変更してはいけません。直すべきはupdatedDate(最終更新日)の方です。

「pubDateが今日じゃなければブロック」という単純なルールのままだと、何日も前に公開した記事をちょっと修正しただけで、毎回引っかかってしまう穴がありました。新規記事と既存記事の修正では、そもそも守るべきルールが違います。

新規記事と既存記事の修正を区別する設計に

そこで、Gitの管理状態を使って「新規記事」か「既存記事の修正」かを判定する設計に変更しました。

function isTracked(relPath) {
  try {
    execSync(`git ls-files --error-unmatch "${relPath}"`, { stdio: 'ignore' });
    return true;
  } catch (e) {
    return false;
  }
}

git ls-filesは「そのファイルがGitで追跡されているか」を教えてくれるコマンドです。これを使うと、以下のように振り分けられます。

状態判定適用するルール
まだ一度もcommitしていない新規ファイル未追跡(untracked)pubDateが今日の日付でなければブロック
過去にcommit済みの既存記事追跡済み(tracked)pubDateの変更をブロック/updatedDateが古ければリマインド

既存記事のチェックでは、Gitの直近のcommit内容(HEAD)と比較して、pubDateが変わっていないかも見ています。

function getHeadPubDate(relPath) {
  try {
    const headContent = execSync(`git show HEAD:"${relPath}"`, { encoding: 'utf8' });
    return extractField(headContent, 'pubDate');
  } catch (e) {
    return null;
  }
}

pubDateが変わっていたらブロックします。Hookが「exit code 2」(処理を終了コード2で止める)を返すと、その内容がClaude Codeに伝わって作業がストップする仕組みです。一方updatedDateが今日になっていない場合は、ブロックまではせず、リマインドだけ出すようにしました(exit code 0 + 標準出力、こちらは処理を止めずにメッセージだけ届けます)。修正ついでにupdatedDateを直し忘れるのはよくあるミスですが、ブロックするほどではないと判断したからです。

3パターンをテストして実際に動かした

作ったあとは、ターミナルで単体テストをしてから本番に組み込みました。

  1. 新規記事・pubDateが今日と違うexit code 2でブロック
  2. 既存記事・pubDateを変更しようとしたexit code 2でブロック
  3. 既存記事・pubDateは正しい・updatedDateだけ古いexit code 0 + リマインドのみ

3パターンとも狙い通りに動きました。実際に既存記事のpubDateを書き換えるテストをしたときは、こんなメッセージが返ってきました。

⚠️ 既存記事のpubDateを変更しようとしています。
  変更前: 2026-05-28T12:00:00
  変更後: 2026-07-04T12:00:00
  pubDateは初出公開日なので変更しないでください。

記事を書くフローのどこでHookが発火するか

このHookは、記事ファイル(src/content/blog/*.md)をEdit・Writeするたびに毎回発火します。1回きりではなく、書いている途中も含めて何度も動きます。

① 新規記事をWriteで作成
   → 発火(この時点ではgit未追跡=「新規記事」判定)
② 検証・修正のたびにEdit
   → 発火し続ける(まだ未追跡なので「新規記事」判定のまま)
③ git add → commit → push
   → ここでHookは発火しない(Bashコマンドのため)
   → この瞬間から「追跡済み」に切り替わる
④(後日)誤字修正などでEdit
   → 発火(今度は「既存記事」判定でチェック)

pushするまでは「新規記事」ルールがずっと効き続け、pushした瞬間から「既存記事」ルールに切り替わります。git addした直後でcommitがまだの場合は、pubDateの変更チェックだけスルーされる(git show HEADが失敗するため)という細かい抜け道もありますが、いつもの「add・commit・pushを一気にやる」運用ではほぼ気にしなくていいケースです。

まとめ

  • Claude Codeに「今日は何日?」と聞いたら、記事のpubDateから逆算した間違った答えが返ってきた
  • 「CLAUDE.mdに書いても守られる保証はあるのか」と聞いたら、正直に「ない」という答えが返ってきた
  • 単純な「pubDateが今日か」チェックだと、既存記事を修正するたびに誤爆する穴があった
  • git ls-filesで新規記事と既存記事の修正を判定し分ける設計にしてから、3パターンのテストで動作確認できた
  • ルールを文書に書くだけでは再発防止にならない。機械的にブロックする仕組みがあって初めて安心できる

CLAUDE.mdは便利ですが、あくまで「守ってくれたらラッキー」な指示書です。絶対に守ってほしいルールがあるなら、Hookで機械的に強制する方が確実だと実感しました。

📖 関連記事


このブログでは、Claude Codeの使い方やハマったポイントを 実際に試した体験ベース で発信しています。お気に入り登録お願いします 🙌

🧑‍💻
この記事を書いた人
AI-Nyanko

某外資系コンサルのインフラエンジニア。Claude Code の実践ノウハウを失敗談も含めて正直に発信しています。

プロフィールを見る →