開発claude-code-tools

Claude Code の累積状態ファイルを gitignore で締め出し、自動掃除する仕組みを整えた

~/.claude/ の中をのぞいたら、見覚えのない JSON が何枚も並んでいた。security_warnings_state_<uuid>.json という名前のファイルが、UUID 違いでずらずらと積み上がっている。1枚ぽつんと開いて「これ何ですかね」と聞いたところから、この日の片付けが始まった。放っておくと git の変更履歴に毎セッション分が乗ってしまう。今日はその正体を突き止めて、二度と手で消さなくていいよう gitignore と自動掃除まで一気に組んだ。

正体を突き止める

ファイルの中身を Claude Code に読ませて、何者か説明させた。返ってきた答えはこうだった。

  • これは Claude Code 本体が持つセキュリティ警告システム(プロンプトインジェクション / 不審なファイル変更の検出機構)の内部状態ファイル
  • ユーザーが触る想定のものではなく、実装都合のメモのようなもの
  • セッションごとに UUID で 1 枚ずつ生成される → 起動を繰り返すと無限に増える

つまり、寿命はセッション終了までしかないのに、ディスクには残り続ける。~/.claude/ を git 管理している自分の構成だと、これが全部 git status に現れて、何もしなくても差分が溜まっていく。「いつか手で消さなきゃ」という気持ちを毎回背負うのが嫌だった。

どう片付けるか方針を決める

自分の中で決めた条件は3つ。

  1. 必要なものは残してコミットする(手元の設定ファイルやルールは履歴に残したい)
  2. 寿命がセッション限りの累積物は git に上げない
  3. 手で掃除しなくていいよう、消える仕組みを仕込む

ここまで決めて、あとの実作業は Claude Code にまとめて回させた。順番はこう指示した。

gitignore更新 → security/ 掃除 → SessionStart hook追加 → cleanup-policyメモ作成 → コミット

実行係は AI、順序と判断は自分、という分担。まず現状の settings.json と既存 hook の書式を確認させてから、一気に流させた。

やったこと

1. gitignore に累積物パターンを追加

security_warnings_state_*.json だけ消しても、同じ性質の「セッション限りの状態ファイル」は他にもある。security/ ディレクトリごと無視対象にして、ついでに同類のランタイム状態もまとめて締め出した。~/.claude/.gitignore に並べたのはこのあたり。

security/
daemon/
daemon.lock
daemon.log
daemon.status.json
jobs/
.last-update-result.json

security/ 配下にはログ用の log.txt も同居しているが、ディレクトリごと無視しても運用上は困らないと判断してそのままにした。

2. 既存の 19 ファイルを削除

.gitignore は新規ファイルを止めるだけで、すでに溜まった分は消えない。security/ 配下にあった security_warnings_state_*.json を 19 ファイル、その場で削除させた。削除後に git status を見たら、累積物が一覧からすっと消えた。.gitignore が効いている手応えがここで確認できた。

3. 14日以上前のファイルを消す SessionStart hook を追加

これが今日の本丸。gitignore で履歴からは消えても、ディスク上には溜まり続ける。手で消す運用に戻したら意味がないので、セッション開始のたびに古いものを掃除する hooksettings.json の SessionStart に入れた。中身は find-mtime +14 で 14 日以上前のものだけを落とすだけ。

find ~/.claude/security -name "security_warnings_state_*.json" -mtime +14 -delete
find ~/.claude/jobs -mindepth 1 -maxdepth 1 -type d -mtime +14 -exec rm -rf {} +

セッションを開くたびに走るので、追加の手動運用はゼロになる。14 日という幅は「直近のデバッグで参照したくなる可能性」と「溜めすぎない」の間で取った値。

4. cleanup-policy メモを作成

仕組みを入れても、半年後の自分は「なんでこの hook があるんだっけ」と忘れる。そこで ~/.claude/rules/cleanup-policy.md に運用方針を書き残した。盛り込んだのは、

  • どのファイルが累積するか(パス・中身・寿命の対応表)
  • gitignore 済みであること
  • SessionStart hook で 14 日以上前を消していること
  • 全消ししたいときの手動コマンド(rm -f ~/.claude/security/security_warnings_state_*.json 等)

未来の自分が読んで「触らなくていい」と即わかる粒度にした。log.txtpins.json のような名前付きファイルは消さない(再生成コストがあるかもしれない)という注意も添えた。

5. 残すべき modified 分を確認してコミット&push

掃除と並行して、手元には残したい変更(設定・ルールの編集)も混ざっていた。コミット前に diff を軽く確認し、消すべきものと残すべきものが取り違えられていないかだけ目視した。問題なかったのでコミットして push まで通した。これで作業ツリーがクリーンになった。

試行錯誤の記録

#検討したこと判断
1該当 JSON を 1 枚ずつ手で消す却下。セッションごとに増えるので追いつかない
2security_warnings_state_*.json だけ gitignore拡張。同類のランタイム状態(jobs / daemon 系)もまとめて締め出した
3gitignore だけで完了とする不十分。履歴から消えてもディスクには溜まる → SessionStart hook を追加
4hook で全削除する却下。直近デバッグで見たい時がある → -mtime +14 で 14 日残す
5仕組みだけ入れて終わる不安。半年後に意図を忘れる → cleanup-policy メモで残す

最初は「1枚消せばいいや」くらいの気持ちだったのが、考えるほど「これは恒久対策にしないと毎回同じ気持ちになる」と分かって、ゴールがじわじわ後ろにずれていった。最終的に gitignore(流入を止める)+ hook(溜まった分を時間で落とす)+メモ(意図を残す)の3点セットに落ち着いた。

学び

  • 寿命がセッション限りの状態ファイルは、見つけ次第「流入を止める+時間で落とす」の2段で対処する。 片方だけだと、履歴は綺麗でもディスクが汚れる、あるいはその逆になる。
  • 手で消す運用は必ず破綻する。 「いつか掃除する」と思った時点で、自動化の hook に置き換えるべきサイン。
  • 仕組みを入れたら、必ず意図をメモに残す。 未来の自分は実装の経緯を覚えていない。cleanup-policy.md の対応表が、次に同種のファイルを見つけたときの判断基準にもなる。
  • 正体不明のファイルは、まず中身を読ませて「誰がいつ何のために生成しているか」を特定するのが先。出どころが分かれば、gitignore で止めるべきか hook で消すべきかが自然に決まる。

関連メモ

  • 運用方針: ~/.claude/rules/cleanup-policy.md
  • 同日には別セッションで、リポジトリ本体の未追跡ファイルを意味のある単位でコミットし直す片付けもやっている(.tmp-* の gitignore 追加、X 検索の生ダンプ残骸の削除など)。「溜まった生成物を整理する」という意味では地続きの作業だった。