Agent-almanac prune-agent-memory

install
source · Clone the upstream repo
git clone https://github.com/pjt222/agent-almanac
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/pjt222/agent-almanac "$T" && mkdir -p ~/.claude/skills && cp -r "$T/i18n/ja/skills/prune-agent-memory" ~/.claude/skills/pjt222-agent-almanac-prune-agent-memory-02a04c && rm -rf "$T"
manifest: i18n/ja/skills/prune-agent-memory/SKILL.md
source content

エージェントメモリのプルーニング

保存されたメモリを監査、分類し、選択的に忘却します。メモリはインフラストラクチャです。忘却はポリシーです。このスキルはそのポリシーを定義します。

manage-memory
がメモリの整理と成長(何を保持するか、どのように構造化するか)に焦点を当てているのに対し、このスキルはその逆に焦点を当てています:何を破棄するか、劣化を検出する方法、忘却が偶発的ではなく意図的であることを保証する方法。2つのスキルは相補的であり、定期的なメンテナンス中に一緒に使用する必要があります。

使用タイミング

  • メモリファイルが大きくなり、関連性について誰も監査していない場合
  • プロジェクトの状態が大幅に変化した(大規模なリファクタリング、リポジトリのリネーム、完了したマイルストーン)ため、メモリが古いコンテキストを参照している可能性がある場合
  • 検索品質が低下している — メモリがシグナルの代わりにノイズを生成している
  • キュレーションなしに多くのメモリエントリを生成した活動の急増後
  • スケジュールされたメンテナンスタスクとして(例:10〜20セッションごと、またはプロジェクトのマイルストーンで)
  • 複数のメモリエントリが同じトピックを微妙なバリエーションでカバーしている場合(重複のドリフト)
  • メモリコンテキストを継承する新しいコラボレーターをオンボーディングする前

入力

  • 必須: メモリディレクトリへのパス(通常
    ~/.claude/projects/<project-path>/memory/
  • 任意: 保持ポリシーのオーバーライド(例:「デプロイに関するすべてを保持」、「デバッグノートを積極的にプルーニング」)
  • 任意: 最後の監査以降の既知のプロジェクト状態の変化(例:「リポジトリがリネームされた」、「JestからVitestに移行した」)
  • 任意: トレンド分析のための以前のプルーニング監査証跡

手順

ステップ1: メモリを列挙して分類する

すべてのメモリファイルを読み、各エントリを4つの次元で分類します。

# メモリディレクトリのインベントリ
ls -la <memory-dir>/
wc -l <memory-dir>/*.md

# 総エントリ数をカウント(トップレベルの箇条書きとヘッダーをカウントすることで近似)
grep -c "^- \|^## " <memory-dir>/MEMORY.md
for f in <memory-dir>/*.md; do echo "$f: $(grep -c '^- \|^## ' "$f") entries"; done

各メモリエントリを以下のタイプのいずれかに分類します:

タイプ説明デフォルト保持
Projectプロジェクト構造、アーキテクチャ、規約に関する事実「skills/ には55のドメインにわたって310のSKILL.mdファイルがある」陳腐化が確認されるまで保持
Decision行われた選択とその根拠「レビューチームにsequentialよりhub-and-spokeを選んだ理由は...」無期限保持
Patternデバッグソリューション、ワークフローの洞察、繰り返し発生する動作「Exit code 5はクォートエラーを意味する — 一時ファイルを使用する」置き換えられるまで保持
Referenceリンク、バージョン番号、外部リソース「mcp-toolsのドキュメント: https://...」陳腐化が確認されるまで保持
Feedbackユーザーの好み、修正、スタイルガイダンス「ユーザーはファイル名にケバブケースを好む」無期限保持
Ephemeral永続メモリに漏れたセッション固有のコンテキスト「現在、issue #42に取り組んでいる」即座にプルーニング

各エントリについて、以下も記録します:

  • 年齢: いつ書き込まれたか、最後に更新されたか?
  • アクセス頻度: このエントリは最近のセッションで役立ちましたか?(最近の作業へのトピックの関連性に基づいて推定)

期待結果: タイプ、年齢、アクセス頻度の推定で分類されたすべてのメモリエントリの完全なインベントリ。エフェメラルエントリはすでに即座の削除のためにフラグが立てられている。

失敗時: メモリファイルが大きすぎるかエントリごとに分類するには構造化されていない場合は、セクションレベルで作業します。個々の箇条書きではなく、セクション全体を分類します。目標はカバレッジであり、粒度ではありません。

ステップ2: 陳腐化を検出する

メモリの主張を現在のプロジェクト状態と比較します。陳腐化はメモリ劣化の最も一般的な形式です。

これらの陳腐化パターンを確認します:

  1. カウントのドリフト: 変化したファイル、スキル、エージェント、ドメイン、チームメンバーのカウント
  2. パスのドリフト: 移動、リネーム、または削除されたファイル、ディレクトリ、またはURL
  3. 状態のドリフト: 解決されたissue、完了したマイルストーン、クローズされたPRが依然としてオープンまたは進行中として説明されている
  4. 決定の逆転: 後に覆されたが元の根拠がメモリに残っている決定
  5. ツール/バージョンのドリフト: 変更されたバージョン番号、APIシグネチャ、またはツール名(例:パッケージのリネーム)
# 真実のソースに対してカウントをスポットチェック
grep -oP '\d+ skills' <memory-dir>/MEMORY.md
grep -c "^      - id:" skills/_registry.yml

# 存在しないファイルへの参照を確認
grep -oP '`[^`]+\.(md|yml|R|js|ts)`' <memory-dir>/MEMORY.md | sort -u | while read f; do
  path="${f//\`/}"
  [ ! -f "$path" ] && echo "STALE: $path referenced but not found"
done

# 古い名前/パスへの参照を確認
grep -i "old-name\|previous-name\|renamed-from" <memory-dir>/*.md

各陳腐化エントリを陳腐化のタイプと現在の正しい値でマークします。

期待結果: 何が変わったかの具体的な証拠を持つ陳腐化エントリのリスト。各陳腐化エントリに推奨アクション: 更新(正しい値がわかっている場合)、確認(不確実な場合)、またはプルーニング(エントリ全体が廃止されている場合)。

失敗時: 外部状態(API、サードパーティのドキュメント、デプロイメントステータス)を参照しているため主張を確認できない場合は、正しいと仮定するのではなく

unverifiable
とマークします。確認不能なエントリは、積極的に役立っていなければプルーニングの候補です。

ステップ3: フィデリティチェックを実行する

メモリが検索されたときに有用なコンテキストを生成するかどうかをテストします。エージェントは自分自身の圧縮されたメモリが忠実であるかどうかを確認することができないため、これが最も難しいステップです — 外部アンカーが必要です。

フィデリティチェックの方法:

  1. ラウンドトリップ検証: メモリエントリを読み、それが説明する実際のプロジェクト状態を確認します。メモリは正しいファイル、正しいパターン、正しい結論に導いていますか?

  2. 圧縮損失の検出: メモリのサマリーを元のソース資料と比較します。50行の議論が2行のメモリに圧縮されたとき、圧縮は実行可能な洞察を保存しましたか、それともトピックラベルだけですか?

    # メモリエントリが導出されたソースを見つける
    # (git log、古いPR、元のファイル)
    git log --oneline --all --grep="<keyword from memory entry>" | head -5
    
  3. 矛盾スキャン: 互いに矛盾するメモリ、またはCLAUDE.md/プロジェクトドキュメントと矛盾するメモリを検索します。

    # カウントにおける潜在的な矛盾を探す
    grep -n "total" <memory-dir>/MEMORY.md
    grep -n "total" CLAUDE.md
    # 値を比較 — 一致するべき
    
  4. ユーティリティテスト: 各メモリエントリについて、「このエントリが削除されたとしたら、次の5セッションで何か問題が起こるか?」と尋ねます。答えが「おそらくない」であれば、エントリは精度に関係なく低フィデリティ値です。

期待結果: 各メモリエントリに今やフィデリティ評価がある: high(検証済みで正確かつ有用)、medium(おそらく正確で時々有用)、low(未確認または稀にしか有用でない)、または failed(検証済みで不正確または矛盾している)。

失敗時: 多くのエントリについてフィデリティチェックが決定的でない場合は、最も高いポテンシャル影響のあるエントリに焦点を当てます。プロジェクトアーキテクチャに関する誤ったメモリは、デバッグトリックに関する誤ったメモリより危険です。詳細レベルよりもスケルトンレベルの事実を優先して確認します。

ステップ4: 選択的削除を適用する

優先順位順に何をプルーニングするかを決定するためにこのデシジョンツリーを使用します:

プルーニングデシジョンツリー(順番に適用):

1. EPHEMERALエントリ(ステップ1の分類)
   → 即座に削除。これらは永続化されるべきではなかった。

2. FAILEDフィデリティエントリ(ステップ3)
   → 即座に削除。不正確なメモリはメモリがないよりも悪い。

3. DUPLICATES
   → 最も完全/正確なバージョンを保持し、他を削除。
   → MEMORY.mdとトピックファイルにまたがる重複がある場合は、トピックファイルのバージョンを保持。

4. 既知の修正を持つSTALEエントリ(ステップ2)
   → エントリが他の点では有用な場合はUPDATE(陳腐化した値を現在のものに変更)。
   → エントリ全体が廃止された場合はDELETE(トピックはもはや重要でない)。

5. 低フィデリティ、低アクセス頻度エントリ
   → 削除。これらはスペースを取っているが価値を提供していない。

6. 完了/クローズした作業についてのMEDIUMフィデリティエントリ
   → アーカイブまたは削除。過去のスプリントの詳細、解決されたインシデント、マージされたPR。
   → 例外: 解決に再利用可能なパターンが含まれている場合は保持。

7. 自由に入手可能なソースを持つREFERENCEエントリ
   → Googleで検索できれば削除。
   → 見つけにくいか、プロジェクト固有のコンテキストがある場合は保持。

各削除について、エントリ、その分類、および削除の理由を記録します(ステップ6で使用)。

期待結果: 削除、更新、保持するエントリの明確なリスト — それぞれに文書化された理由がある。保持/削除の比率はメモリの健全性に依存する。維持されているメモリは5〜10%をプルーニングするかもしれず、放置されたものは30〜50%をプルーニングするかもしれない。

失敗時: デシジョンツリーが多くのエントリについて曖昧な結果を生み出す場合は、より厳しいフィルターを適用します: 「今知っていることを知っていたとしたら、このエントリを今日書くか?」そうでなければ、削除の候補です。プルーニングに傾けます — 間違ったメモリに対処するより事実を再学習する方が簡単です。

ステップ5: 予防フィルターを適用する

将来のメモリ汚染を防ぐために「保存しないもの」のルールを定義します。書き込み時にフィルタリングされるべきだったパターンについて既存のメモリを確認します。

永続メモリになるべきでないパターン:

パターンなぜ
セッション固有のタスク状態次のセッションまでに陳腐化「現在、issue #42をデバッグしている」
中間的な推論結論ではない「アプローチAを試したが、...のために機能しなかった」
デバッグ出力/スタックトレースエフェメラルな診断データ「エラーは: 234行目のTypeError...」
正確なコマンドシーケンス脆弱で、バージョン依存
npm install foo@3.2.1 && ...
を実行する」
感情的/トーン的なノートアクション可能でない「ユーザーはイライラしているようだった」
CLAUDE.mdの複製すでにシステムプロンプトにある「プロジェクトは依存関係にrenvを使用している」
未確認の単一の観察誤っている可能性がある「APIレート制限は100/分だと思う」

これらのパターンのいずれかが既存のメモリに見つかった場合は、ステップ4の削除リストに追加します。

将来のセッションが新しいメモリを書く前に参照できるように、MEMORY.mdまたは

retention-policy.md
トピックファイルにフィルタールールを文書化します。

期待結果: メモリディレクトリに文書化された予防フィルタールールのセット。これらのパターンに一致する既存エントリは削除フラグが立てられる。

失敗時: フィルタールールの文書化が時期尚早に感じられる場合(メモリが小さく、汚染が最小限)、文書化をスキップしますが、既存の違反を見つけるためにフィルターを適用します。ルールはメモリディレクトリが成熟したときに後で形式化できます。

ステップ6: 監査証跡を書く

忘却自体がレビュー可能になるように、すべての削除をログに記録します。プルーニングログを作成または更新します。

<!-- In <memory-dir>/pruning-log.md or appended to MEMORY.md -->

## Pruning Log

### YYYY-MM-DD Audit
- **Entries audited**: N
- **Entries pruned**: M (X%)
- **Entries updated**: K
- **Staleness found**: [list of stale patterns detected]
- **Fidelity failures**: [list of entries that failed verification]

#### Deletions
| Entry (summary) | Type | Reason |
|-----------------|------|--------|
| "Currently working on issue #42" | Ephemeral | Session-specific, stale |
| "skills/ has 280 SKILL.md files" | Project | Count drift: actual is 310 |
| "Use acquaint::mcp_session()" | Pattern | Package renamed to mcptools |

プルーニングログを簡潔に保ちます。それは説明責任のために存在し、考古学のためではありません。ログ自体が大きくなった場合は、古いエントリを要約します: 「2025: 3回の監査、合計47エントリがプルーニングされた(主にカウントのドリフトとエフェメラルの漏れ)。」

期待結果: 何が削除されたかとその理由を文書化したタイムスタンプ付きのプルーニングログエントリ。ログはメモリ自体と一緒にメモリディレクトリに保存される。

失敗時: 別のログファイルを作成することが過剰に感じられる場合(1〜2エントリのみがプルーニングされた)、代わりにMEMORY.mdに簡単なノートを追加します:

<!-- Last pruned: YYYY-MM-DD, removed 2 stale entries -->
。どんな記録も黙って削除するよりは良い。

ステップ7: 保護されたメモリを指定する

特定のメモリエントリは、年齢、アクセス頻度、またはフィデリティスコアに関係なく、プルーニングから免除されるべきです。これらは、失われた場合に再構築するのに多大な労力を必要とする代替不能なコンテキストを表しています。

保護されたメモリの基準:

カテゴリなぜ保護されるか
アーキテクチャの決定「ネストではなくフラットなスキルディレクトリを選んだ」根拠は後で再導出された場合に失われる
ユーザーアイデンティティの好み「常にケバブケースを使用する」、「自動コミットしない」明示的なユーザーの意図、推測できない
セキュリティ監査の結果「最後の監査: 2025-12-13 — PASSED」タイムスタンプ付きのコンプライアンス証拠
リネーム/マイグレーションの記録「リポジトリはX日Y日にYにリネームされた」クロスリファレンスの整合性はこれに依存する

指定方法: 保護されたエントリを

<!-- PROTECTED -->
インラインでマークするか、プルーニングログに
protected
リストを維持します。ステップ4のデシジョンツリーは削除ルールを適用する前に保護状態を確認する必要があります。

保護の解除: 保護されたエントリをプルーニングするには、最初に指定を明示的に削除し、プルーニングログに理由を文書化します。この2ステッププロセスにより、高価値なメモリの偶発的な削除を防ぎます。

期待結果: 保護されたエントリはすべてのプルーニングパスを生き残る。プルーニングログは保護の追加または削除を記録する。

失敗時: 保護されたセットが大きくなりすぎる場合(総エントリの30%以上)、基準を見直します — 保護は「重要な」エントリのためではなく、代替不能なコンテキストのためです。重要だが再構築可能な事実は通常のプルーニング対象のままにしておくべきです。

ステップ8: プルーニング後の再合成

削除後、残りのメモリは断片化している可能性があります — クロスリファレンスが削除されたエントリを指し、トピックファイルが一貫性を失い、MEMORY.mdにギャップが生じる可能性があります。再合成は構造的な整合性を回復します。

再合成チェックリスト:

  1. 壊れた参照を解決する: 削除されたコンテンツへのリンクについて残りのエントリをスキャンします。参照を削除または更新します。
  2. 関連する断片をマージする: プルーニングによって同じトピックの重複する側面をカバーする2つのエントリが残った場合、それらを1つの一貫したエントリにマージします。
  3. トピックファイルの構造を更新する: トピックファイルがコンテンツの50%以上を失った場合、残りをMEMORY.mdに戻し、トピックファイルを削除することを検討します。
  4. コールドメモリを分類する: プルーニングを生き残ったが最近アクセスされていないエントリを確認します:
    • 不使用によるコールド: トピックはアクティブなプロジェクトの目標と一致するが、それを生成した特定のフェーズは過ぎている。保持 — そのフェーズが再開されたときに再び関連性を持つ可能性がある(例:アクティブな開発中のCRANサブミッションノート)。
    • 無関係によるコールド: トピックは常に周辺的だった — 一時的な実験、切り接触する調査、または置き換えられたアプローチ。次のプルーニングサイクルでの削除のためにフラグを立てる。
  5. MEMORY.mdの一貫性を確認する: MEMORY.mdを最初から最後まで読みます。プロジェクトについての一貫したストーリーを語るべきであり、ランダムな事実の集合として読まれるべきではありません。

期待結果: プルーニング後のメモリは構造的に健全 — 孤立した参照なし、冗長な断片なし、一貫性のないトピックファイルなし。コールドエントリは将来のプルーニング決定のために分類されている。

失敗時: 再合成によってプルーニングが積極的すぎた(重要なコンテキストが失われた)ことが明らかになった場合は、プルーニングログを確認し、監査証跡から再構築します。これが監査証跡が存在する理由です。

ステップ9: メモリドリフトからの回復

メモリドリフトは、保存された事実が黙って誤りになるときに発生します — 常に誤っていたからではなく、根底にある現実が変化したのにメモリが更新されなかったからです。ドリフトの回復は、プルーニングする代わりにインプレースでメモリを修正しようとします。

ドリフト検出のトリガー:

  • メモリの主張が現在のツール出力またはファイルコンテンツと矛盾する
  • メモリのカウントまたはバージョン番号がレジストリまたはロックファイルと一致しない
  • メモリのパスが「ファイルが見つかりません」を返す
  • 依存関係に関するメモリがリネームまたは廃止されたパッケージを参照している

回復プロシージャ:

  1. ドリフトを特定する: メモリの主張を現在のグラウンドトゥルース(gitログ、レジストリ、実際のファイル)と比較する
  2. 回復可能性を評価する: 現在のプロジェクト状態から正しい値を決定できるか?
    • はい →
      [corrected YYYY-MM-DD]
      アノテーションを付けて現在の値でインプレースでメモリエントリを更新する
    • いいえ → エントリを
      unverifiable
      とマークし、プルーニングのためにフラグを立てる
  3. 原因をトレースする: これは段階的なドリフト(カウントがゆっくり分岐した)か、離散的なイベント(リネーム、マイグレーション)か?離散的なイベントは複数のエントリに影響することが多い — 兄弟エントリをスキャンする。
  4. 再発を防ぐ: ドリフトが頻繁に変化する値(カウント、バージョン)に影響する場合は、メモリがその値を追跡すべきかどうか、または代わりに真実のソースを参照すべきかどうかを検討します: 「317スキル」の代わりに「現在のカウントについてはskills/_registry.ymlを参照」。

期待結果: ドリフトしたメモリは可能な場合はインプレースで修正され、コンテキストが保存される。修正できないエントリはプルーニングのためにフラグが立てられる。予防ルールにより将来のドリフトが減少する。

失敗時: ドリフトが広範囲にわたる場合(エントリの20%以上)、メモリは段階的な修正ではなく完全な再構築が必要かもしれません。その場合は、現在のメモリディレクトリをアーカイブし、最初から始め、検証を通過したエントリのみを選択的に再インポートします。

バリデーション

  • すべてのメモリファイルがインベントリされ、エントリがタイプで分類された
  • 現在のプロジェクト状態に対して陳腐化チェックが実行された
  • 少なくとも1つのフィデリティチェック方法が適用された(ラウンドトリップ、圧縮損失、矛盾スキャン、またはユーティリティテスト)
  • 削除の決定がデシジョンツリーの優先順位に従っている
  • 文書化された理由なしにエントリが削除されなかった
  • 予防フィルタールールが文書化または適用された
  • プルーニングログが何を、いつ、なぜ削除したかを記録している
  • プルーニング後もMEMORY.mdが200行以内に収まっている
  • 残りのメモリが正確である(プロジェクト状態に対してスポットチェック済み)
  • MEMORY.mdのプルーニング参照によって孤立したトピックファイルが作成されなかった
  • 保護されたエントリが指定され、すべてのプルーニングパスを生き残る
  • プルーニング後の再合成が壊れたクロスリファレンスを解決し、断片をマージした
  • コールドエントリが将来のプルーニング決定のために不使用 vs 無関係として分類された
  • ドリフトしたエントリが可能な場合は単純に削除されるのではなくインプレースで修正された

よくある落とし穴

  • 検証なしのプルーニング: エントリが「古く見える」からといって、依然として正確で有用かどうかを確認せずに削除する。年齢だけでは削除基準になりません — 最も価値のあるメモリの中には、依然として真実であるアーキテクチャの古い決定がある。
  • 自己検証フィデリティ: 圧縮されたメモリを読んで「はい、これは正しいようだ」と結論するエージェントはフィデリティチェックではありません。フィデリティには外部アンカーが必要です: プロジェクトファイル、gitログ、レジストリのカウント、実際のツール出力。アンカーなしでは一貫性をチェックしているだけで、正確性をチェックしていない。
  • 監査証跡なしの積極的なプルーニング: 何が削除されたかを記録せずにエントリを削除する。プルーニングされた事実を将来のセッションが必要とするとき、監査証跡は何が起こったかを説明し、メモリを再構築するのに十分なコンテキストを含んでいる可能性がある。
  • メモリとしてのプルーニング決定: 「Xをプルーニングすることにした。なぜなら...」を通常のメモリエントリとして書かない。それはプルーニングログにのみ入ります。メモリ管理に関するメモリエントリはメタ汚染です。
  • 予防フィルターを無視する: 既存のエントリをプルーニングするが、同じパターンが再発するのを防ぐルールを確立しない。フィルターなしでは、次の10セッションが削除したのと同じエフェメラルエントリを再作成します。
  • すべてのタイプを平等に扱う: DecisionメモリとFeedbackメモリはほぼ決してプルーニングすべきでない — それらはユーザーの意図と根拠を表しています。ProjectとReferenceメモリが主なプルーニング対象です。なぜなら変化する状態を追跡するから。
  • 圧縮と破損を混同する: 複雑なトピックを1行にまとめたメモリは圧縮されており、破損していません。圧縮が実行可能な洞察を失った場合にのみフィデリティ失敗としてフラグを立てる、単に詳細を失った場合ではなく。
  • 過度のピン留め: あまりにも多くのエントリを保護としてマークすることはプルーニングの目的を無効にします。エントリの30%以上が保護されている場合、基準が緩すぎます。代替不能なコンテキストを保護し、単に重要な事実ではなく。
  • 再合成ループ: 再合成中に断片をマージすると、それ自体が次のサイクルでプルーニングが必要な新しいエントリを作成する可能性があります。マージを最小限に保つ — 明らかに同じトピックをカバーするエントリのみを組み合わせる。プルーニングパス中に新しい洞察を合成しない。

関連スキル

  • manage-memory
    — メモリを整理して成長させるための補完スキル。完全なメモリメンテナンスのために一緒に使用する
  • meditate
    — どのメモリがノイズを作り出しているかを明らかにするかもしれないクリアリングとグラウンディング
  • rest
    — 時には最良のメモリメンテナンスはメモリメンテナンスをしないこと
  • assess-context
    — 推論コンテキストの健全性の評価。メモリの品質が直接影響する