Session .jsonl transcript silently deleted while session folder remains — deletion pattern doesn't match simple age-based retention
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
cleanupPeriodDaysis not set in either~/.claude/settings.jsonor~/.claude.jsonfileCheckpointingEnabled: 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:
- 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.
- 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
.jsonland its folder are now completely gone — no trace at all on disk, not even thetool-results/cache. This is a different, more severe symptom than "folder survives, only.jsonlis missing."
What I ruled out
- No cron/systemd timer or user script touches
~/.claude/projects/on this machine (verified: crontab, systemd timers,grep -racross all local scripts). - Not the documented
/compactbehavior: found a liveisCompactSummary: trueentry inside a transcript that survived — it uses the samesessionId, appended within the same.jsonlfile. Compaction does not create a new file or delete the old one. - Not a VM reboot:
last rebootshows 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.jsonlintact. 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
- What is the actual default retention period when
cleanupPeriodDaysis unset? - Is there a way to fully disable transcript deletion (not just increase the number of days)?
- Why would a session's
.jsonlbe deleted while itstool-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.
3 Comments
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: 36500is set in~/.claude/settings.json(effectively "never delete").Evidence of loss:
.jsonlfiles gone.Mitigation in place: hourly
rsyncbackup of~/.claude/projects/to a separate directory — the only reliable protection given that the explicit setting is not honored.This corroborates that the
cleanupPeriodDays ?? 30fallback is actively destructive even with an explicit user setting. Happy to provide logs or run diagnostics.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),
cleanupPeriodDaysunset (default 30).Symptom: Discovered 2026-09-21 after a reboot: three sessions missing from the
claude --resumepicker. On disk, each session's<uuid>.jsonlis 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:
.jsonl..jsonlvanished, leaving orphaned session directories — same selective pattern as the OP.Timeline / other observations:
~/.claude/.last-cleanupmtime: 2026-09-20 16:51 local. One deleted session was still active at 10:36 that morning (6h before the cleanup stamp).--resumewas 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.bridge-sessionrecords withcse_/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: 365explicitly 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) and0e881d4c-4446-4bd1-8c32-46d25ca9d8f0(active 2026-09-22/23). Same selective fingerprint:.jsonlgone, orphaned~/.claude/projects/<slug>/<uuid>/dirs remain with intactsubagents/*.meta.jsonandtool-results/.Key new datapoints:
cleanupPeriodDayshad been set to 365 in~/.claude/settings.jsonsince 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..jsonlfiles 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.~/.claudeexisted 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.@joscodar thanks — your fingerprint matches ours exactly (
.jsonlgone,<uuid>/side dirs intact, recent sessions hit while older ones in the same folder survive), and yourcleanupPeriodDays: 365datapoint closes the door on the retention sweep. We also seebridge-sessionrecords 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>.jsonlthat 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:entrypointisclaude-vscodeorcli(interactive), neversdk-cli/sdk-tsautomation;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 listsclaude-vscode. Rewriting that field toclaude-vscodeinside the.jsonlmakes them appear and resume normally in VS Code / code-server — we verified this on a real session. We now do it automatically forsdk-clisessions 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.