0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeで「会話が消えた」と思ったら、まずこのスクリプトを走らせる——セッションは消えていない

0
Posted at

Claude Code を使っていて、こんな経験はないでしょうか。

  • VS Code でフォルダを切り替えたら、サイドバーの会話の一覧が空になった
  • 拡張の「Past conversations」を開いたら、昨日までの会話が一件も出てこない
  • 長い作業の途中で文脈が自動で要約され、前に話したことが消えた気がする

どれも「データが消えた」ように見えます。けれど結論から言うと、ほとんどの場合、会話は一件も消えていません。Claude Code の会話は、起動したフォルダごとにあなたのディスクへ丸ごと保存され続けていて、見えなくなるのは表示の側がそのフォルダの分しか出していないからです。

この記事では、まず「消えた」会話を全部のフォルダから一覧して特定する自己診断のスクリプトを渡し、そのうえで取り戻す手順を説明します。スクリプトの中で使っている保存場所・cwd の記録・--continue での読み戻しは、すべて自分の環境のディスクで直接確かめた事実です。一方、各 UI が「空に見える」内部の表示のフィルタの値は、起票での報告に基づく伝聞です。両者は分けて書きます。

まず走らせる:消えた会話を全部のフォルダから探す

下のスクリプトを cc-find-sessions.sh として保存して走らせると、すべてのフォルダの会話を新しい順に一覧します。各会話について、それを始めた作業フォルダ、そのまま貼れる再開コマンド、見分け用の冒頭の発言が出ます。

#!/usr/bin/env bash
# Claude Codeの「消えた」会話を全フォルダから探す自己診断。
# 使い方:  bash cc-find-sessions.sh            … 全セッションを新しい順に一覧
#          bash cc-find-sessions.sh キーワード  … 会話の中身でキーワード一致のものだけ
kw="${1:-}"
python3 - "$kw" <<'PY'
import sys, os, glob, json, time
kw = sys.argv[1] if len(sys.argv) > 1 else ""
rows = []
for f in glob.glob(os.path.expanduser("~/.claude/projects/*/*.jsonl")):
    if os.path.getsize(f) == 0:
        continue
    cwd = first = ""
    hit = (kw == "")
    try:
        with open(f, encoding="utf-8", errors="ignore") as fh:
            for line in fh:
                if kw and kw.lower() in line.lower():
                    hit = True
                if cwd and first:
                    continue
                try:
                    o = json.loads(line)
                except Exception:
                    continue
                if not cwd:
                    cwd = o.get("cwd", "")
                if not first:
                    m = o.get("message")
                    if isinstance(m, dict) and m.get("role") == "user":
                        c = m.get("content")
                        if isinstance(c, str):
                            first = c.strip().replace("\n", " ")[:60]
                        elif isinstance(c, list) and c and isinstance(c[0], dict):
                            first = str(c[0].get("text", "")).strip().replace("\n", " ")[:60]
    except Exception:
        continue
    if not hit:
        continue
    rows.append((os.path.getmtime(f), cwd or "?", first or "(冒頭の発言なし)"))
rows.sort(reverse=True)
for mt, cwd, first in rows[:40]:
    ts = time.strftime("%Y-%m-%d %H:%M", time.localtime(mt))
    print(f'{ts}  {cwd}')
    print(f'    再開: cd "{cwd}" && claude --resume')
    print(f'    冒頭: {first}\n')
PY

実行すると、こういう出力になります(自分の環境での実際の出力です)。

2026-06-27 09:58  /home/me/projects/cc-loop
    再開: cd "/home/me/projects/cc-loop" && claude --resume
    冒頭: まず ~/ops/handoff/latest.md(前セッションの引き継ぎ)と task-check を読み…

2026-06-27 06:24  /home/me/projects/myapp
    再開: cd "/home/me/projects/myapp" && claude --resume
    冒頭: ログイン画面のバリデーションを直したい。まず…

「あの会話、どのフォルダで始めたか思い出せない」というときは、会話の中で出たキーワードで絞り込めます。

bash cc-find-sessions.sh ログイン画面

出力の 再開: の行をそのまま端末に貼れば、その会話に戻れます。

なぜこれで見つかるのか:会話はフォルダごとに保存されている

Claude Code の会話は、起動したときの作業フォルダ(カレントディレクトリ)ごとに保存されます。場所はここです。

~/.claude/projects/<フォルダの絶対パスのスラッシュをハイフンに置換>/

たとえば /home/me/projects/myapp で起動した会話は ~/.claude/projects/-home-me-projects-myapp/ の下に、一つの会話につき一つの .jsonl ファイルとして貯まります。先頭のスラッシュもハイフンになります。

自分の環境で数えると、11 のフォルダにまたがって計 260 個の会話の .jsonl がありました。別のフォルダを VS Code で開いても、これらのファイルは一切変化しません(減りも消えもしません)。サイドバーが空に見えるのは、いま開いているフォルダに紐づく会話だけを一覧に出しているからで、前の会話は別のフォルダ用のディレクトリに無傷で残っています。

.jsonl の各行には、その会話を起動したフォルダの絶対パスが cwd として、各やりとりの時刻が timestamp として記録されています。上のスクリプトは、この cwd を読んで「どのフォルダのものか」を復元し、ファイルの更新時刻で新しい順に並べているだけです。だから、フォルダ名のエンコード(スラッシュをハイフンに置換する規則)を手で組み立てる必要はありません。日本語などの非ラテン文字を含むフォルダ名は、保存ディレクトリの名前のうえで別の文字に潰れて見分けにくくなることがあるので、cwd の中身から復元するこの方法のほうが確実です。

取り戻す3つの手順(実機で確認済み)

1. そのフォルダに戻って続きから開く

cd /path/to/そのフォルダ
claude --continue      # そのフォルダの「直近の会話」をそのまま続ける
# または
claude --resume        # そのフォルダの会話の一覧から選ぶ

--continue(短く -c)は、ヘルプにも「カレントディレクトリの直近の会話を続ける」と明記されていて、カレントディレクトリに紐づいています。だから VS Code の拡張のサイドバーが何を表示していようと、端末で目的のフォルダに cd してこのコマンドを打てば、拡張の表示のフィルタを完全に迂回して会話を取り戻せます。これがいちばん確実な脱出口です。

2. 中身から探す

上のスクリプトにキーワードを渡すか、直接 grep します。

grep -l '探したい単語' ~/.claude/projects/*/*.jsonl

3. 要約(compaction)で前の話が消えた気がするとき

長い会話の途中で文脈が自動で要約されると、「さっきまでの細かいやりとりが消えた」ように感じます。けれど、要約は表示と次の文脈づくりのためのもので、元の .jsonl の行は消えません。自分の進行中の会話の .jsonl を種類ごとに数えると、要約の前のあなたの発言・応答・ツールの呼び出しが全部残っていました。失った詳細を読み返したいときは、その .jsonl をそのまま開けば、元のやりとりが時系列で全部あります(一行が一つの JSON なので jqgrep で扱えます)。

本当に消える数少ない場合と、その予防

ここまでは「消えたように見えるが消えていない」話です。逆に本当に取り返せなくなるのは、.jsonl そのものを削除してしまうときです。たとえば、

  • セッションを掃除するコマンド(プロジェクトの purge など)を、よく確かめずに走らせて、別のプロジェクトの会話まで巻き添えで消す
  • 保存ディレクトリを手で rm する、あるいは同期や掃除のスクリプトが巻き込む
  • 前述の非ラテン文字のフォルダ名の衝突で、同じ保存ディレクトリに別のフォルダの会話が同居し、片方を消したつもりが両方消える

共通するのは、「消す側の操作」を実行の前に止められなかったことです。会話の .jsonl は普通の操作では消えませんが、削除系のコマンドを一度誤って走らせると戻りません。

このクラスの事故(よく確かめずに消す・上書きする・巻き添えで飛ばす)を実行の前で機械的に止める仕組みは、PreToolUse のような実行前のフックで表せます。破壊的な操作をブロックするフックの設定の例は、無料の cc-safe-setup にまとめています。データ消失や暴走の実例と症状別の対処を一冊にしたものは Claude Code 事故防止ハンドブック にあります。「消えたように見えるが消えていない」を正しく見分けられると、慌てて余計な削除をして本当に消す、という二次災害を避けられます。

まとめ

  • 「会話が消えた」と思ったら、まず cc-find-sessions.sh を走らせる。たいてい全部そこにある。
  • 会話はフォルダごとに ~/.claude/projects/<エンコードしたパス>/*.jsonl に保存され、別のフォルダを開いても消えない。空のサイドバーは表示のフィルタで、データ消失ではない。
  • 取り戻すには、そのフォルダに cd して claude --continueclaude --resume
  • 要約で消えた気がしても、元の履歴は .jsonl に全部残っている。
  • 本当に消えるのは削除系の操作を誤ったときだけ。そこは実行の前に止める仕組みで防ぐ。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?