mcpField
S
session-recover

session-recover

github.com/ngmeyerエージェントワークフロー4326 回インストール今日更新
リポジトリ

session-recover について

session-recoverは、作業ディレクトリのパス違いでプロジェクトのセッションや永続メモリが分かれた場合に使うClaude Code向けスキルです。重複した領域を特定し、メモリを統合または評価して、会話ログを削除せずにアーカイブします。

主な機能

  1. 01重複するプロジェクト領域の検出
  2. 02正規のメモリパスの選定
  3. 03メモリファイルの統合または評価
  4. 04孤立した会話ログのアーカイブ
  5. 05ファイル数の照合

活用シーン

  1. 01セッションで欠落したメモリの復旧
  2. 02/resume に表示されないセッションの確認
  3. 03シンボリックリンクや移動後のパスの統合

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ngmeyer/skills --skill session-recover

インストール後、Claude Code で/session-recoverを入力して読み込まれたか確認します。

同梱ファイルreferences/merge-example.mdscripts/inventory.sh

詳細

/session-recover — 重複する Claude Code プロジェクトディレクトリを手動で統合する

Claude Code は、プロジェクトごとのセッショントランスクリプトと永続メモリを ~/.claude/projects/{encoded-cwd}/ に保存します。エンコードされた cwd は絶対パスで、英数字以外のすべての文字が - に置き換えられます。同じ論理プロジェクトを指す異なる cwd パス(実ディレクトリとそのシンボリックリンク、外部マウントのパスと ~/Projects/ のショートカット、Linux ユーザーが /home/me から /Users/me に移動した場合など)は、完全に別々の名前空間を生成します。/resume のセッション一覧も、メモリディレクトリも別々になり、相互に参照できません。

このスキルでは、重複を検出し、メモリを正規の場所に統合し、孤立したトランスクリプトをアーカイブして、今後のセッションで分裂が再発しないよう教訓を記録します。

このスキルを使う場面

  • セッションを開いたときにメモリディレクトリが空なのに、過去のセッションで項目を追加した記憶がある
  • claude --resume に表示されるセッション数が、想定より少ない
  • 末尾のトークンが一致する ~/.claude/projects/-*-foo/ ディレクトリが2つ見つかった
  • 会話内のセッション間メモリ参照を解決できない([[some-memory]] のリンク先が見つからない)
  • ~/.claude/projects/ 全体をプロジェクト名で grep すると、複数の一致が返る

上記のいずれにも当てはまらない場合、このスキルで行うことはありません。早めに終了し、ユーザーに伝えてください。

基本原則

正規パスは、Claude Code の現在のシステムプロンプトで指定されているパスです。 ハーネスがセッションを開始すると、次のように通知します。

You have a persistent, file-based memory system at /Users/me/.claude/projects/{ENCODED}/memory/

これが採用するパスです。末尾のトークンが似ているほかのすべてのパスは、候補から外れるパスです。ユーザーが別のパスを正規パスにしたい場合は変更できますが、デフォルトではハーネスが選んだパスを採用してください。

手順

Phase 1 — 識別:重複するプロジェクトディレクトリを見つける

オプション引数をプロジェクト名のトークンとして使います。省略された場合は、cwd の末尾のコンポーネント(basename "$PWD")または会話から推定します。

bash ~/.claude/skills/session-recover/scripts/inventory.sh <project-token>

このスクリプトは、次の情報とともに ~/.claude/projects/*<token>*/ ディレクトリをすべて一覧表示します。

  • jsonl セッションファイル数+合計サイズ+最も新しいファイルの mtime
  • メモリディレクトリ内の項目数
  • エンコードされたパスが Lexar(Volumes-Lexar)、home-Projects(Users-.*-Projects)、またはその他のどれに該当するか

次の場合は停止して、ユーザーに確認してください。

  • 一致が1つだけの場合 → 重複はありません → 終了
  • 一致が3つ以上ある場合 → 続行する前に、どれを正規パスにするか確認
  • 候補の jsonl の mtime が大きく異なる場合(例:一方は先週、もう一方は今日アクティブだった)→ 両方を統合するかユーザーに確認
Phase 2 — 識別:採用するパスを選ぶ

デフォルトでは、現在のセッションのシステムプロンプトにある「persistent, file-based memory system at …」で指定されたパスを選びます。

そのパスが重複ディレクトリの候補ではない場合(例:ユーザーがプロジェクト外からこのスキルを実行している場合)、どれを正規パスにするかユーザーに確認してください。通常は、作業を始めるときに実際に cd するパスか、プロジェクトレベルの CLAUDE.md で「canonical」と指定されているパスです。

Phase 3 — メモリをマージする

各候補から外れたパスについて、そのメモリの内容を採用するパスに移動します。必ず mv を使い、cp は使わないでください。これにより、候補から外れたパスのメモリディレクトリが空になり、情報源が競合しなくなります。

WINNER=~/.claude/projects/<canonical-encoded-path>
LOSER=~/.claude/projects/<loser-encoded-path>

mkdir -p "$WINNER/memory"
mv "$LOSER/memory/"* "$WINNER/memory/" 2>/dev/null
rmdir "$LOSER/memory" 2>/dev/null

競合の処理: 両方に同じ名前のファイルがある場合(最も多いのは MEMORY.md)、上書きしてはいけません。両方を読み、採用するパス側に統合版を手作業で書き込み、その後で候補から外れたパス側のコピーを削除してください。通常、これは MEMORY.md(インデックスファイル)だけに発生します。

Phase 4 — jsonl トランスクリプトをアーカイブする

候補から外れたパスにある jsonl セッションファイルとセッションごとのサブディレクトリを ~/.claude/archive/ に移動します。rm は使わないでください。アーカイブは元に戻せますが、削除は元に戻せません。

ARCHIVE_DIR=~/.claude/archive/$(basename "$LOSER")
mkdir -p "$ARCHIVE_DIR"
mv "$LOSER"/*.jsonl "$ARCHIVE_DIR/" 2>/dev/null
# Also archive any UUID subdirs (per-session checkpoint dirs)
for d in "$LOSER"/[0-9a-f]*-[0-9a-f]*/; do
    [ -d "$d" ] && mv "$d" "$ARCHIVE_DIR/"
done
rmdir "$LOSER" 2>/dev/null

ディレクトリが空でないため rmdir "$LOSER" が失敗した場合、残っているものを一覧表示してユーザーに確認してください。通常は、明示的な処理が必要な余分なファイル(.DS_Store や標準外のサブディレクトリ)が残っています。

フェーズ 5 — 教訓をメモリーとして記録する

今後のセッションで、このプロジェクトには dual-cwd の危険性があるとわかるよう、勝者のメモリーディレクトリに feedback タイプのメモリーエントリーを書き込みます。

---
name: dual-cwd-memory-split-{project}
description: Memory dir is path-derived from cwd. Two cwd paths for the same project produced separate memory namespaces; merged YYYY-MM-DD.
metadata:
  type: feedback
---

The {project} project is reachable via:
- `{canonical-cwd-path}` — canonical
- `{loser-cwd-path}` — symlink/mirror/alias

These produce separate `~/.claude/projects/-*/` namespaces. Memory was merged into the canonical path on YYYY-MM-DD; jsonl transcripts archived to `~/.claude/archive/{loser-encoded}/`.

**How to apply:** always `cd` into `{canonical-cwd-path}` before `claude`. If a future session lands at the other path and finds an empty memory dir, re-run /session-recover before doing real work.

次に、勝者のメモリーディレクトリにある MEMORY.md に、1 行のポインターを追加します。

- [Dual-cwd memory split](feedback_dual_cwd_memory_split_{project}.md) — memory namespaces merged YYYY-MM-DD; cd into the canonical path
フェーズ 6 — 検証
ls "$WINNER/memory/" | wc -l   # entry count, should be sum of both sides minus dedup
ls "$LOSER" 2>/dev/null         # should report "No such file or directory"
ls ~/.claude/archive/$(basename "$LOSER")/  # archived jsonls + dirs

(V2)照合ゲート — 何も失われていないことを証明します。 成功を宣言する前に、件数を照合します。移動する前に、フェーズ 3 で winner_before と loser_count を記録し、winner_after == winner_before + loser_count − dedup_count を確認します。ここで dedup_count は、手動で統合した同名ファイルの数です。計算が合わない場合は、停止して差異を示します。ファイルの欠落はサイレントな損失を意味し、このスキルで決して起こしてはならない結果です。件数が照合できる(またはユーザーが記録済みの重複排除を承認する)まで、成功を報告しないでください。

最終状態は、照合の式(winner_before + loser − dedup = winner_after)を含む 3 行の表でユーザーに報告します。

フェーズ 7 — /compact を提案する

Claude Code の /compact スラッシュコマンドは、進行中のセッションを整理された要約にまとめます。マージ後の会話には「これを見つけて、あれを移動した」という詳細が大量に含まれていますが、後で役立つものではありません。ユーザーに /compact を実行するよう伝えてください(これはユーザーレベルのコマンドなので、自分では実行できません)。

バリエーション:レガシーな孤立メモリー(無条件にマージせず、内容を評価する)

上記のフェーズ 3〜4 は、敗者が同じ現在の作業を反映した稼働中のミラーであることを前提としています。そのため、そのメモリーを勝者に移しても問題ありません。しかし、孤立したメモリーがプロジェクトフォルダーの移動前から存在するレガシーな名前空間である場合もあります(例:プロジェクトが数か月間 /Users/me/Projects/foo にあり、その後 /Volumes/Drive/Projects/foo に移動された場合)。その場合、孤立したメモリーは古く、移動前の状態、完了済みのバックログ、置き換えられた事実が含まれています。これを正規のディレクトリに無条件にマージすると、古い内容で現在のメモリーを再び汚染します。 孤立したメモリーの更新日時が正規のディレクトリより何週間も古い場合や、孤立した MEMORY.md に明らかに以前のプロジェクト状態が記載されている場合は、これを検出します。

その場合は、フェーズ 3 のすべてを mv する手順を、ファイルごとの評価に置き換えます。

  1. 孤立したメモリーファイルをすべて読みます。 それぞれを分類します(ファイルの移動、機能のリリース、事実の変化があるため、現在のリポジトリ/コードで主張を検証します)。
    • 残すもの → リポジトリ:リモートエージェント/共同作業者に必要な決定事項、注意点、または製品アイデアで、リポジトリ(docs/、CLAUDE.md)にも正規のメモリーにも存在しないもの。→ リポジトリに記録します(docs/decisions/ の ADR、docs/ のナレッジドキュメント、またはアイデアのバックログ)。
    • 残すもの → ローカル:「X をしないこと。すでに処理済みです」のような、現在も有効な動作上のガイダンス。→ 正規のメモリーディレクトリにコピーし、インデックスに追加します。
    • シークレットの場所:トークン/認証情報の保存場所や、環境変数と環境の対応関係を示すもの。→ 正規のシークレットインベントリメモリーに統合します。プライベートリポジトリであっても、絶対にコミットしないでください。
    • 古い情報:置き換えられた状況、完了済みのバックログ、古い監査記録。→ アーカイブします。
  2. 残すものを所定の場所(リポジトリまたは正規のメモリー)に復元し、シークレットの場所に関する情報をローカルのインベントリに照合して統合します。
  3. 古い孤立ファイルは、孤立したメモリーディレクトリ内の _archived-pre-migration/ サブフォルダーにアーカイブします。削除せず、正規のディレクトリにもマージしないでください。
  4. 孤立した MEMORY.md を墓標化します。孤立した <old-path> のミラーであること、正規の名前空間とリポジトリが信頼できる情報源であること、ファイルがアーカイブされたことを記したメモに置き換えます。これにより、古いパスから開始した今後のセッションが、古い情報を信頼するのを防ぎます。
  5. 「孤立したファイル → 判定 → 対応」の表を報告します。本当に価値のある項目を復元した場合は、目立つように記載します。それこそがこの作業の成果です(例:バックログに追加されないまま保留されていた製品アイデア)。

フェーズ 4(トランスクリプトのアーカイブ)はスキップします。依頼がない限り、レガシーのトランスクリプトはそのままにします。また、フェーズ 5 もスキップします(分断の再発を防ぐため、dual-cwd に関するフィードバックメモリーは正規のディレクトリに記録する価値があります)。

このスキルで行わないこと

  • 2 つの jsonl トランスクリプトを 1 つのセッションにマージすることはできません。 これは不可能です。Claude Code にマージ操作はありません。このスキルでは、アクティブなセッションのトランスクリプトを残し、その他をアーカイブします。
  • ユーザーから後続の依頼として明示的に求められない限り、コード、CLAUDE.md、計画ドキュメントは編集しません。 対象はメモリと jsonl のみです。マージ内容を反映すべき古い計画/ステータスドキュメントがプロジェクトにある場合は、スキルの実行後に更新を依頼できます。
  • 何も削除しません。 アーカイブは元に戻せますが、rm は元に戻せません。
  • 呼び出しのたびには実行しません。 フェーズ 1 で重複が 0 件と判明したら、そこで終了してその旨を伝えます。無理に作業を作り出さないでください。

注意点

  1. mv と cp: 必ず mv を使ってください。cp を使い、元ファイルの削除を忘れると、今後のセッションが敗者側に保存され、新しいエントリを書き込むため、そのメモリディレクトリが増え続けます。流出を止めるには、元の場所から削除する必要があります。

  2. MEMORY.md のマージ時の衝突: 通常、インデックスファイルは両方に存在します。むやみに mv しないでください。mv -n を使うと、敗者側のコピーが同じディレクトリに残り、インデックスが 2 つできてしまいます。両方を読み、手作業でマージしてから、敗者側のコピーを削除してください。

  3. セッションごとの UUID サブディレクトリ: Claude Code は <uuid>.jsonl ファイルと並べて <uuid>/ チェックポイントディレクトリを作成します。これらは主にセッション再開用の状態を保持します。jsonl と一緒にアーカイブし、孤立したまま残さないでください。

  4. rmdir "$LOSER" が失敗する場合: macOS の .DS_Store や、残存した todos/ ディレクトリが原因であることがほとんどです。再試行の前に内容を一覧表示してください。反射的に rm -rf を実行しないでください。

  5. 現在のセッションが敗者側のディレクトリにある可能性があります。 ユーザーが正規ではない cwd からセッションを開始した場合、現在の .jsonl は敗者側に書き込まれています。会話の途中でアーカイブしないでください。実行中のセッションによる書き込みが失敗します。先に /exit するようユーザーに伝えるか、現在のセッションの jsonl は除外して、残りをアーカイブしてください。

  6. プロジェクト名の一部が一致する場合: 2 つのプロジェクト名に共通のトークンがある場合(例:api と api-gateway)、インベントリスクリプトは両方を返します。ファイルを移動する前に、候補の全リストを必ずユーザーに提示し、確認してください。

  7. 「どちらのトランスクリプトのほうが新しいか」を推測しないでください。 これはコンテンツのマージに関する問題であり、状態のマージに関する問題ではありません。このスキルの役割はメモリの名前空間を統合することです。アクティブなセッションのトランスクリプトは元の場所に残します。

変更履歴

V2(2026-05-27)

skillforge optimize により最適化しました。率直な注記: 外部の成果に関する調査は限定的でした。これは、Claude Code の特定の仕組みに対する手順的なスキルであり、掘り下げるに値する重要な最先端の情報はありません。守るべき本当の成果は マージ時にメモリを一切失わないこと であるため、V2 の変更は調査結果の取り込みではなく、安全性の強化です。

  • 整合性確認ゲート(フェーズ 6) — winner_after == winner_before + loser − dedup を検証します。不一致があれば停止します。「完了したように見える」状態を「何も失われていないと証明できる」状態に変えます。既存のアーカイブして削除しないルールと組み合わせることで、マージはすでに元に戻せます。
  • 調査結果に基づく追加はありません(エージェントメモリの 3 層モデルは、旧オーファン向けのバリエーションにおけるリポジトリ/ローカル/シークレットの振り分けにすでに反映されています)。

関連項目

  • references/merge-example.md — 異なる 2 つの cwd のマージを最初から最後まで解説する、サニタイズ済みの例です。
  • scripts/inventory.sh — フェーズ 1 のヘルパーです。
  • 旧オーファン向けのバリエーションでは、リポジトリ側への移行に向けて、残すべき情報(ADR、ドキュメント、アイデアのバックログ)を リポジトリに 復元します。このスキルでは、名前空間の整理とトゥームストーンの作成を行います。

コメント