Session .jsonl transcript silently deleted while session folder remains — deletion pattern doesn't match simple age-based retention

Status Open
Reported on v2.1.272
Maintainer reply None cached
Activity 3 comments · opened Sep 18, 2026

Summary

Session transcripts (~/.claude/projects/<project>/<uuid>.jsonl) disappear from disk while the session's auxiliary directory (~/.claude/projects/<project>/<uuid>/tool-results/, which caches SessionStart hook output) remains intact. This affects real, substantial interactive conversations — not just short/automated sessions — and the temporal pattern does not match a simple age-based retention sweep.

Environment

  • Claude Code CLI: 2.1.272 (native binary, /joao/.local/bin/claude)
  • Claude Code VS Code extension (code-server): 2.1.276
  • OS: Ubuntu 24.04.4 LTS, self-hosted VPS
  • cleanupPeriodDays is not set in either ~/.claude/settings.json or ~/.claude.json
  • fileCheckpointingEnabled: true (used only for /rewind, per docs — confirmed not related)

Observed behavior (measured directly on disk)

Across multiple project directories under ~/.claude/projects/, most session folders (identified by a valid UUID) no longer have their companion .jsonl transcript, while the folder itself — and its tool-results/ cache from the SessionStart hook — still exists:

| Project | Session folders | Live .jsonl | Folders without .jsonl |
|---|---|---|---|
| Project A | 75 | 16 | 65 |
| Project B | 199 | 57 | 152 |
| Project C | 118 | 80 | 41 |

I cross-referenced this against a separate local database (a memory plugin that records content_session_id + started_at + first user prompt for every session that ever ran) to distinguish two very different situations:

  1. Automated/non-interactive sessions (skill runs triggered by cron, autonomous sub-agent task executions, git-worktree sessions) — most of the missing-transcript count falls here (e.g. 163 of 218 in one project). This may be expected/acceptable.
  2. Real interactive human conversations with substantial content — a smaller but recurring subset. Example: a session that ran for ~8 minutes, produced 11 distinct pieces of work (document analysis, calendar events created, files edited), and both its .jsonl and its folder are now completely gone — no trace at all on disk, not even the tool-results/ cache. This is a different, more severe symptom than "folder survives, only .jsonl is missing."

What I ruled out

  • No cron/systemd timer or user script touches ~/.claude/projects/ on this machine (verified: crontab, systemd timers, grep -r across all local scripts).
  • Not the documented /compact behavior: found a live isCompactSummary: true entry inside a transcript that survived — it uses the same sessionId, appended within the same .jsonl file. Compaction does not create a new file or delete the old one.
  • Not a VM reboot: last reboot shows uptime since 2026-08-20, no reboot around the dates the deletions occurred.
  • Not a simple age-based sweep relative to "today": in one project, a session from yesterday has already lost its .jsonl, while a session from 29 days ago still has its .jsonl intact. This directly contradicts "delete anything older than N days, checked against today's date."

What's unclear from the docs

settings.json reference documents cleanupPeriodDays only as "control how many days Claude Code retains transcripts before automatic deletion" — it doesn't state the default value when the key is absent, nor how to disable the sweep entirely, nor whether the sweep trigger is time-based (a periodic check) or event-based (e.g. only evaluated when a new session starts in that same project directory — which would better explain why deletions cluster in bursts rather than following a smooth daily pattern).

Question

  1. What is the actual default retention period when cleanupPeriodDays is unset?
  2. Is there a way to fully disable transcript deletion (not just increase the number of days)?
  3. Why would a session's .jsonl be deleted while its tool-results/ folder (or, in the more severe case, the entire session folder) is not touched by the same sweep — and in the severe case, why would a real, substantial, non-trivial interactive session be eligible for deletion at all after only ~6 weeks?

Happy to provide more specific session IDs/timestamps privately if useful for debugging — omitted here since this repo is public and some of that data touches personal projects.

View original on GitHub ↗

3 Comments

joaovictorrodriguesreis · 23 days ago

Cross-linking with #41458 — we believe we are hit by the same bug, with an additional data point from a Linux VPS environment.

Environment: Ubuntu 24.04 VPS, Claude Code CLI + VS Code extension via code-server. Auto-updating.

Configuration: cleanupPeriodDays: 36500 is set in ~/.claude/settings.json (effectively "never delete").

Evidence of loss:

  • An independent witness — the claude-mem memory system, which logs every session — shows 218 sessions recorded for one project directory; only ~85 .jsonl files remain on disk. 163 sessions silently deleted.
  • The husk pattern matches other reports: session UUID directories survive with subagent artifacts intact, main .jsonl files gone.
  • The deletion pattern does not match age-based pruning: an 8-minute-old session (a document review with 4 calendar events created) vanished, while some older sessions survived. Nothing older than ~30 days remains, though.
  • The VS Code extension session list corroborates: only recent sessions with human-typed messages appear.

Mitigation in place: hourly rsync backup of ~/.claude/projects/ to a separate directory — the only reliable protection given that the explicit setting is not honored.

This corroborates that the cleanupPeriodDays ?? 30 fallback is actively destructive even with an explicit user setting. Happy to provide logs or run diagnostics.

joscodar · 20 days ago

Adding a Windows datapoint — same fingerprint as the OP, on a much older version.

Environment: Windows 11 Pro (10.0.22631), Claude Code v2.1.207 (CLI, interactive), cleanupPeriodDays unset (default 30).

Symptom: Discovered 2026-09-21 after a reboot: three sessions missing from the claude --resume picker. On disk, each session's <uuid>.jsonl is gone from ~/.claude/projects/<project-slug>/, while all side data survived:

  • ~/.claude/projects/<project-slug>/<uuid>/ (subagents/, workflows/ incl. saved workflow scripts and journals)
  • ~/.claude/file-history/<uuid>/ (all snapshots intact)
  • ~/.claude/tasks/<uuid>/, ~/.claude/session-env/<uuid>/

Affected session IDs: 3ac388a6-aa6b-4119-80c1-955508d5f209, 1b72fd9f-633a-4654-b482-c9c7422018fc, adb3b41a-bc35-4d40-8263-48061275e030.

Why this isn't the 30-day retention sweep:

  • The three deleted sessions were created 2026-09-16/17 and last active 2026-09-17 to 2026-09-20 — i.e., 3–5 days old at deletion.
  • Older transcripts in the same project folder survived: sessions created 8/23 and 8/24 (one idle since 8/23) still have their .jsonl.
  • Per the docs, the legitimate retention sweep removes the transcript and its side data as a group; here only the .jsonl vanished, leaving orphaned session directories — same selective pattern as the OP.

Timeline / other observations:

  • ~/.claude/.last-cleanup mtime: 2026-09-20 16:51 local. One deleted session was still active at 10:36 that morning (6h before the cleanup stamp).
  • Deletion window: between each session's last activity and 2026-09-21 06:15, when --resume was first checked. A hard reboot happened early on 9/21, but the files had been idle for many hours to days before it — an unclean shutdown doesn't remove idle files, so I don't believe the reboot is the cause.
  • Recycle Bin empty, no VSS shadow copies — unrecoverable.
  • Possibly irrelevant, but noting since the mechanism is unknown: other (surviving) sessions in the store have bridge-session records with cse_/session_ IDs appended (cloud session bridging was active on this install).

So: OP's Linux data + this report = the selective .jsonl-only deletion of recent sessions reproduces on at least two platforms and across a wide version range (2.1.207 → 2.1.272).

---

UPDATE — second incident on the same machine, 2026-09-24, with cleanupPeriodDays: 365 explicitly set.

Two more sessions lost from the same project store (still v2.1.207): b81d5f99-454b-4655-a126-07270a60d67f (created 2026-09-23 ~08:15 local, active until ~17:36 the same day) and 0e881d4c-4446-4bd1-8c32-46d25ca9d8f0 (active 2026-09-22/23). Same selective fingerprint: .jsonl gone, orphaned ~/.claude/projects/<slug>/<uuid>/ dirs remain with intact subagents/*.meta.json and tool-results/.

Key new datapoints:

  • cleanupPeriodDays had been set to 365 in ~/.claude/settings.json since 2026-09-21 (after the first incident). The deletion happened anyway, on sessions less than 2 days old — this rules out the retention sweep entirely, misconfigured or otherwise.
  • Deletion window: 2026-09-23 ~17:36 → 2026-09-24 08:00 local (bounded below by the session's last activity, above by a scheduled backup job that found the files already gone). A Windows-update restart killed the 4–5 open CLI terminals inside that window; several surviving sessions' .jsonl files show final appends at ~10:05–10:07 on 9/24 as the machine came back. So in both incidents an unclean termination is nearby, but in the first incident the files had been idle for days before the reboot — termination may be a trigger for some sessions and not others, or coincidental.
  • A daily 08:00 backup of ~/.claude existed this time and still missed both files: born after one run, deleted before the next. If you're mitigating with backups, run them more than daily.
joaovictorrodriguesreis · 20 days ago

@joscodar thanks — your fingerprint matches ours exactly (.jsonl gone, <uuid>/ side dirs intact, recent sessions hit while older ones in the same folder survive), and your cleanupPeriodDays: 365 datapoint closes the door on the retention sweep. We also see bridge-session records in the affected project stores, for what it's worth.

Your last point is the one that shaped our mitigation: a daily backup can't catch a transcript that is born and deleted between two runs. Here is what we ended up with on the Linux VPS, in case it helps anyone reading:

1. Backup every 5 minutes. A cron job rsync -as ~/.claude/projects/ into a separate directory (append-only, never deletes). A full run over ~600 MB / ~1,300 files takes about 2 seconds, so the frequency costs nothing.

2. Automatic restorer. In the same job, after the copy, any <project>/<uuid>.jsonl that exists in the backup but is missing from ~/.claude/projects/ is copied back with its original mtime preserved (shutil.copy2) — a restored file with a fresh mtime could be picked up again by whatever is deleting them. The resume picker is built from the files on disk, so a restored session simply reappears and can be continued. Rules we found necessary:

  • only restore sessions whose entrypoint is claude-vscode or cli (interactive), never sdk-cli/sdk-ts automation;
  • never overwrite a file that already exists; if the live file is smaller than the backup (session deleted and then recreated from scratch), just log a conflict for manual handling;
  • email a notice when something is restored, deduplicated so each session is reported once.

One caveat we learned the hard way: a restorer can't tell "deleted" from "moved". When we moved a project folder to a new path, it "restored" 17 old sessions back to the old location.

3. A related, separate problem: sessions started from claude remote-control (we run it as systemd services) never show up in the VS Code extension's session list. They are recorded with "entrypoint":"sdk-cli", and the picker only lists claude-vscode. Rewriting that field to claude-vscode inside the .jsonl makes them appear and resume normally in VS Code / code-server — we verified this on a real session. We now do it automatically for sdk-cli sessions with a human first message that have been idle for 30+ minutes (so we never touch a file a live process is still writing). Reported separately as #94546.

None of this fixes the root cause, but since the restorer went in we haven't had to hand-recover anything.