Repository navigation
Silent retention cleanup deletes session transcripts with no warning, opt-in, or recovery #59248
Description
Summary
A user actively working in Claude Code (Cursor extension, anthropic.claude-code-2.1.141-darwin-arm64) lost the ability to resume, view, or recover all Claude Code conversation transcripts in a given workspace older than the current session, including a session from the previous day, because a built-in cleanup process silently deleted those transcripts from disk. The user received no prompt, no warning, and no Trash-style soft-delete. The retention setting (cleanupPeriodDays) was never surfaced, never set explicitly, and the observed retention behavior is inconsistent with the documented 30-day default — sessions newer than 30 days are still missing. When the user discovered the loss, the Cursor resume picker presented an empty workspace history, leaving the user with no in-product hint that data had ever existed there.
Specific concerns
-
No consent prompt. Cleanup runs out of the box with no install-time disclosure or first-run dialog. Users who treat their conversation history as durable working knowledge are silently mistaken about the persistence model.
-
No UI surface for retention.
cleanupPeriodDaysis documentation-only. There is no UI in Cursor's Claude Code extension or the CLI to view current retention, see when next cleanup will run, see what will be deleted, or cancel a pending cleanup. -
Hard delete, no Trash. Deleted transcripts go straight to
unlink(). No soft-delete folder, no grace period, no--restorecommand, noclaude restoresubcommand. macOS Trash is bypassed. -
Observed behavior diverges from documented retention. With a documented 30-day default and today's date 2026-05-14, sessions from 2026-04-14 onward should survive. In this workspace, the most recent surviving transcript material is 2026-03-04 — 71 days ago. Either the documented default is wrong, the cleanup uses a different rule (delete-on-extension-update, delete-on-session-end, delete-on-
/clear, delete-on-cursor-restart), or there's a separate deletion path triggered by something other than the 30-day timer. -
Subagent orphan pattern is a smoking gun. When the parent
<sessionId>.jsonlis deleted but the<sessionId>/subagents/subdirectory is left behind, the result is dead weight: tens of MB of subagent transcripts that reference a parent session that no longer exists, cannot be resumed, and are not surfaced in any UI. Either the cleanup should be transactional (delete the dir AND the subagents together, OR delete neither), or both should be retained. -
Cleanup is timed to session start — the worst possible moment. Running cleanup ~12 minutes after a Claude Code session starts means a user who opens Claude Code today to look up what they discussed yesterday triggers the very cleanup that deletes yesterday's transcript. The interaction is destructive at the exact moment the user most needs the data.
-
Cross-version risk. The Cursor Claude Code extension updated on 2026-05-13 (the day of the lost session). The user attempted version rollback to recover — which had no effect, because the data lives in
~/.claude/and is not version-coupled. Anthropic should clarify whether extension upgrades trigger their own cleanup, and whether transcripts written by an older extension version are at risk on first run of a newer version. -
No telemetry or audit trail. No log of what was deleted, when, or why. A user has no way to confirm what they lost or build a case for restoration.
Suggested fixes
- Surface a retention disclosure on first run; default to longer or infinite retention until the user opts in.
- Add a soft-delete tier: move deleted transcripts to
~/.claude/projects/<workspace>/.trash/for N days before unlink, withclaude restoreto recover. - Make cleanup transactional: never delete a parent
.jsonlwhile itssubagents/directory still has content. - Don't run cleanup at session-start; run it on session-end, or on an idle timer that respects the "user just opened Claude Code" signal.
- Add an explicit log of cleanup actions to
~/.claude/cleanup.logwith timestamps and deleted file list. - Expose
cleanupPeriodDays(and acleanupEnabledboolean) in a settings UI, not just via JSON. - Reconcile documented vs. actual retention behavior; if reproducible, treat it as a bug.
Reproduction conditions
- macOS 25.5.0 (Darwin)
- Cursor IDE with Claude Code extension
anthropic.claude-code-2.1.141-darwin-arm64 - A
cwdcontaining a literal space (e.g.Chrome Extentions/proj-universal-capture-cursor) — produces dual slug variants under~/.claude/projects/. - No
cleanupPeriodDaysoverride in~/.claude/settings.json. - File of interest:
~/.claude/.last-cleanup(rewritten each cleanup pass; contains a single ISO timestamp).
On-disk evidence
~/.claude/.last-cleanupupdated 2026-05-14 13:13:20 PT (today). File born 2026-05-07.- 8 orphan
<sessionId>/subagents/directories survive in the affected workspace (Feb 12 – Mar 4 content, ~15 MB, 72 files), with no parent.jsonlfor any of them. ~/.claude/file-history/confirms 6 session UUIDs were active on 2026-05-13 — none of those UUIDs have any surviving session directory or transcript anywhere in~/.claude/projects/.- User's
~/.claude/settings.jsoncontains nocleanupPeriodDayskey — running on whatever the binary default is.
Timeline (2026-05-14 PT)
| Time | Event |
|---|---|
| 12:59:22 | First Claude Code session of the day starts (a different Cursor workspace) |
| 13:01:02 | Second Claude Code session starts in the affected workspace |
| 13:13:20 | Cleanup pass runs and updates .last-cleanup |
The cleanup runs ~12 minutes after session start. The deletion of yesterday's transcripts is most plausibly attributed to this pass.
Activity
github-actions commentedon May 14, 2026
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
FTSBrand commentedon May 14, 2026
Thanks for the duplicate suggestions. I've reviewed the three referenced issues and want to flag this report as same bug family but with materially new evidence — please keep it open rather than auto-closing.
Cross-reference
cleanupPeriodDays: 99999was set and ignored. Lists "version upgrade reset" as suspected root cause.What this report adds that the three above do not
anthropic.claude-code-2.1.141-darwin-arm64). The three predecessors are all CLI. This widens the scope..last-cleanupmtime: the cleanup pass runs ~12 minutes after a Claude Code session starts. This is the worst possible moment — a user opening Claude Code to recall yesterday's session triggers the cleanup that deletes yesterday's session. Suggests the fix in [BUG] cleanupPeriodDays: 99999 ignored — 490 sessions silently deleted despite explicit setting #41458 root-cause analysis is on the right track (cleanup running before settings fully resolve, or in the wrong subprocess context).Ask
Please retain this issue and consolidate with #46621 / #41458 as part of an active investigation rather than closing as a duplicate. The new platform (Cursor extension), version (2.1.141), and timing evidence (cleanup-at-session-start, same-day-upgrade-correlation) materially advance the diagnosis. Happy to provide the full local forensic report on request.
Local forensic file path on the affected machine for cross-reference:
docs/transcripts/claude-code/2026-05-14_session-recovery-forensics.mdghh1111 commentedon May 24, 2026
+1, 1800+ husks on macOS, v2.1.150, default settings, May 24 cleanup wiped years of work. Have now spent 9+ hours debugging with no way to get them back. Claude code silently deleted all of my /project session jsonl files with no warning, no asking for permission. Then when claude code suggested filing a bug report here, it immediately got flagged by the bot saying it was a duplicate. So how many more people are living through this who are not being allowed to echo the issue here? This is more than an "oops". This is catastrohpic for long term development work if you aren't backing up your local files. I generally have no reason to - claude project files would have been the only reason. Who knew that anthropic would decide all of my chats with all of the logic, reasoning, decisions and why should just be deleted with no warning. I echo the user who said "whose files did they think those were anyway"?
It's wiping out MY DATA and hard work.
garrettmoss commentedon May 25, 2026
I hit this issue and built a recovery tool for the macOS + Time Machine case: https://github.com/garrettmoss/restore-claude-history
Some caveats re scope:
~/.claude/projects/. Doesn't touch Claude Desktop session storage (YET. Working on it.)The README also has the one-line
~/.claude/settings.jsonchange ("cleanupPeriodDays": 36500) that's supposed to defang the documented cleanup going forward. Worth setting even if you don't need recovery — (though per #41458 the setting isn't always honored, which is partly why a recovery path matters).Open to suggestions/fixes if needed.
Lost months of chat history on a personal project, and much else, on many different Claude "updates".
ojura commentedon May 25, 2026
Filed #62250 with the same loss; folding it here as a duplicate. Adding the mechanism and a stopgap that complement this thread.
Deletion is keyed on file mtime, not the transcript's own last-activity timestamp.
cleanupOldSessionFilesinsrc/utils/cleanup.tswalks~/.claude/projects/<slug>/and callsunlinkIfOld, which deletes any*.jsonl/*.castwithstat.mtime < now - cleanupPeriodDays. Because mtime is externally mutable, anything that touches it flips the outcome: a restore (cp,tar -x,rsyncwithout-a), a sync client, or a script that sets mtimes to a session's true (old) last-activity date makes a present session look old, and it is silently deleted on the next sweep. (I hit exactly this: normalizing session mtimes for picker chronology made ~30-day-old sessions eligible and deleted 11.) Keying retention on the last in-file messagetimestampinstead of mtime would close this whole class of accidental loss.cleanupPeriodDays: 0is an overloaded footgun.getCutoffDate()with0returns now (deletes everything), andshouldSkipPersistence()treats=== 0as "don't persist". So the value that intuitively reads as "off" instead wipes all transcripts and stops writing new ones.The large-value workaround is not reliable (see #41458 / #45735): processes started with
--setting-sources local, or the SDK'ssettingSources: [](including autonomously spawned subagents), run cleanup that ignorescleanupPeriodDaysfrom~/.claude/settings.jsonand fall back to the default 30. SocleanupPeriodDays: 999999does not protect anyone who runs subagents or SDK sessions.A
SessionStartbackup hook is a nice stopgap until this is fixed: it copies transcripts out of the deletion path, independent of the buggy setting. The on-disk JSONL is append-only (/rewindorphans a dead branch and keeps appending; it does not shrink the file), so one high-water-mark backup per file is lossless: copy only when the backup is missing or the live file has grown. Keying on grew-only (not mtime, not size-differs) makes it both mtime-immune and shrink-safe.~/.claude/hooks/backup-sessions.sh:~/.claude/settings.json:{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "~/.claude/hooks/backup-sessions.sh" } ] } ] } }Even if cleanup deletes a transcript, the latest state survives outside
~/.claude/projects/.Fix directions echoing this thread: retain by the in-file last-activity timestamp (not mtime); archive or trash instead of
unlink; make it opt-in or use a much longer default; and make the restricted-setting-source paths honorcleanupPeriodDays.Already lost sessions to this (on ext4)? An after-the-fact recovery toolkit - volatility-ordered: stop writes, dump live
claude --resumeprocess memory + webview state, take backup/ext4-journal wins, then raw-disk carve + journal-extent recovery - is at ojura/claude-skills (recover-deleted-sessions-ext4). It's triage, not a fix; theSessionStartbackup hook above is what keeps you from needing it.garrettmoss commentedon May 25, 2026
@ojura — thanks for the mtime/cleanup analysis above, it's the most informative comment I've seen so far. I've updated my repo's notes to credit it (and walked back some over-confident framing as a result): https://github.com/garrettmoss/restore-claude-history/blob/master/NOTES.md#why-updates-seem-to-trigger-this
Your
SessionStarthook is the right shape for forward-looking backup, which is the gap my Time Machine recovery tool doesn't fill (yet). I'd like to use it as the reference implementation for abackup_claude_history.pyalongside the restore script — credit you, link this comment, then extend with a CLI, restore-from-backup verb, retention policy, etc. Want to be involved (co-author, reviewer, anything), or happy for me to just run with it and credit?Also noticed your repo
claude-patches— that's a separate impressive rabbit hole. Likely not too much overlap with what I'm doing but good to know it exists.ojura commentedon May 25, 2026
@garrettmoss sure, I will have my Claude talk to your Claude 😁
KirkPX commentedon May 27, 2026
Adding a data point on scope, because this one hurt.
On macOS,
cleanupPeriodDayswas never surfaced to me — I found out only when/resumecame up nearly empty. On disk: 773 session folders, but only 132 surviving.jsonltranscripts. Roughly 640 conversations spanning January through mid-May were silently deleted, each leaving an orphanedsubagents//tool-results/folder behind. Like the OP, my observed retention was far shorter than the documented 30 days — survivors only go back about a week.No warning, no soft-delete, no recovery path: no Trash, and any backup or snapshot I had postdated the deletion. The only thing I could partially salvage was the prompts I'd typed (from
history.jsonl) — none of Claude's actual work.Months of context, gone with zero notice. Please make this opt-in, or at minimum warn before deleting and soft-delete to Trash rather than unlinking. Thanks for tracking this.
ojura commentedon May 27, 2026
@KirkPX have a look at the .jsonl carving skill in ojura/claude-skills, it might save some chats.
suenamis commentedon Jun 3, 2026
Adding a Windows Desktop data point.
Lost two sessions in the same project (
Billy AI FishandBilly AI Fish 2, 44 and 52 days old) to today's startup cleanup on Claude Code Desktop 2.1.156 / Windows 11. Both were explicitly maintained as long-running reference threads — the verbatim chat was active continuation context for ongoing hardware/software work on a Raspberry Pi side-project, not idle scratch.After the cleanup, the sidebar shows "Sitzung nicht auf dem Datenträger gefunden" ghost entries (same symptom as #62959). The
.jsonlfiles in~/.claude/projects/<project>/and the corresponding%APPDATA%\Claude\local-agent-mode-sessions\<workspace>\<project>\local_<sid>\.claude\projects\…paths were already unlinked, with no Recycle Bin entry (cleanup usesfs.unlink).Two concrete points for the fix discussion:
Setting
cleanupPeriodDays: 0is rejected by schema validation with a message recommending a large number instead (workaround:36500). That validation error is currently the only place the workaround is documented — discoverable only after data loss. Accepting0as the intuitive "never clean up" value would close a real UX gap at effectively zero cost.Auto-memory
MEMORY.md/project_*.mdfiles under~/.claude/projects/<project>/memory/survived and made partial reconstruction possible — genuinely good design. But a curated summary isn't a substitute for the verbatim flow that captures why particular decisions were made; you can rebuild the what from memory files, not the reasoning behind tried-and-rejected approaches.Strong +1 to soft-delete to the OS Recycle Bin, UI exposure of
cleanupPeriodDays, and a pre-cleanup warning with per-session pin.33 remaining items
loophole64 commentedon Sep 18, 2026
That was not an AI generated response. it doesn't even have correct capitalization in some spots. English is clearly not their first language.
davidlovas commentedon Sep 18, 2026
You're looking at the wrong one dude. #59248 (comment)
loophole64 commentedon Sep 18, 2026
I see. Still, English is not their first language. I would give them a pass on having an LLM write a post for them.
C3B2W23 commentedon Sep 19, 2026
Looks like Anthropic added some new options to prevent this, but it does not seem to affect or fix wiping files from the scratchpad. I'm still losing scripts / work, details that need to be recreated, wasting time, wasting tokens, and wasting my money.
roygonen commentedon Sep 21, 2026
This just happened to me as well. The most frustrating feeling ever.
I was looking for an old chat of a project i wanted to continue, and everything disappeared. Completely. Non-recoverable.
Why the hell would you do that? all the transcripts are saved locally on my machine, why do you care for retention, this is my responsibility.
You should disable this completely, I don't want any user consent BS.
Let me own my data.
God.
jako479 commentedon Sep 22, 2026
I'm with @roygonen. Why the hell would any transcripts be deleted, ever? And especially silently and automatically?! And this issue has been open FOR MONTHS! What in the hell? Plus, the cleanupPeriodDays setting has an issue that has also been open for months saying it can't actually be relied on to prevent deletion of session transcripts. I guess it's time to finally look at the open-source models.
davidlovas commentedon Sep 22, 2026
You might not be able to recover it exactly as it was, but you can reconstruct it from the history.jsonl
BasedGPT commentedon Sep 23, 2026
Hey suenamis,
The missing
.jsonlfiles in both locations and the “Sitzung nicht auf dem Datenträger gefunden” rows point to missing transcript files rather than a session-list display problem. If an earlier Windows Volume Shadow Copy still exists (System Protection must have been enabled), it may hold a copy.I built
BasedGPT/claude-code-session-recoveryfor this file layer. From that repository, runpython tools/diagnose.pyand follow the exact next command it prints. If it routes to a Windows VSS scan, that scan starts as a dry run and needs an elevated PowerShell or Command Prompt. Compare the proposed.jsonlcopies before restoring anything.Before restoring files with old timestamps, set
"cleanupPeriodDays": 36500in~/.claude/settings.jsonand make sure no process uses--setting-sources localor SDKsettingSources: [], which bypass that setting. Keep an outside copy of the current~/.claude/projects/and%APPDATA%\Claude\local-agent-mode-sessions\trees until the restored sessions open.Hope this helps, if my tools are able to help you, would appreciate a ⭐ :)
davidqyc commentedon Sep 30, 2026
For anyone who has not lost the transcript yet, I’d treat retention and independent preservation as two separate layers.
First, set a large positive
cleanupPeriodDaysvalue in~/.claude/settings.jsonand use/statusto confirm that the settings file actually loaded. I would not use0as “keep forever”.But this thread also has several reports where a large value did not protect every execution path, so for sessions you genuinely cannot afford to lose, keeping an independent copy outside
~/.claudestill makes sense.I maintain Session Preserve:
https://github.com/davidqyc/session-preserve
I wrote a focused guide here:
https://github.com/davidqyc/session-preserve/blob/main/docs/claude-code-session-backup.md
Important scope note: it is not a recovery tool, not a continuous sync/backup daemon, and not a way to restore or
/resumea session. It reads one explicitly selected top-level session JSONL while that transcript still exists and produces a readable package plus provenance/coverage metadata and a manifest that can be verified later. The package does not include the raw JSONL, tool payloads, or subagent transcripts, so if you may want to resume a session later, keep a plain copy of the session files as well.If your transcript has already been deleted, the recovery tools already linked earlier in this thread are the more relevant option.
davidlovas commentedon Sep 30, 2026
Is anthropic going to address this issue because at this point this thread is a collection of billboards for redundant vibe coded solutions
chid commentedon Sep 30, 2026
The solution is simple: set a large positive cleanupPeriodDays value in ~/.claude/settings.json.
davidlovas commentedon Sep 30, 2026
Yes but there's evidence that this setting has been unreliable in the past and also the main complaint is that auto cleanup should be opt-in.
samvallad33 commentedon Oct 1, 2026
Losing 1,800+ sessions to an mtime-keyed sweep is brutal, and ojura's forensics make the trap plain: retention keyed to stat.mtime rather than the transcript's own last timestamp means anything that touches file mtimes — a restore without
-a, a sync client, mtime normalization for picker chronology (which cost them 11 sessions) — quietly re-arms the deletion. The half I'd add to the fixes above: make the record itself tamper-evident. Strata keeps an append-only, hash-chained log of what the agent did; entries can't be silently pruned or rewritten, and every write returns a receipt you can replay. A cleanup pass could still run — it just couldn't be invisible. Local-first, nothing leaves the machine the transcripts lived on: https://github.com/samvallad33/vestige(Disclosure: I work on Vestige, the project linked here.)
MoralStrike commentedon Oct 2, 2026
Had a month-long break due to family stuff. Come back and my chats are all gone.
Lost important chats with important data.
How is this not an opt-in?? Who came up with this preposterous "feature"?
Ironically, Anthropic TOS allow it to keep our chats for 5 years, yet they delete them on our side after a month??
How about you guys delete it on your side instead?
willphule commentedon Oct 4, 2026
Another data point, from the Claude Desktop Code tab (Windows 11, desktop 2.19675.0, bundled Claude Code 2.1.286)
12 of my 84 Code-tab sessions now open with "session not found on disk". All 12 were last used between Apr 1 and Jun 15, 2026. Their transcripts were deleted by the
cleanupPeriodDayssweep (default 30), which I didn't know existed. The desktop sidebar kept listing all 12 by title, so I only found out months later when I opened them. By then nothing could bring them back. The files were unlinked rather than moved to the Recycle Bin, the SSD has TRIM on, and my backup only keeps deleted files for 30 days. One of them was a 20-turn working session on a project I'm still building.2.1.286 now skips transcripts with a desktop
entrypoint, which helps. It came too late for these 12, and two gaps remain:.desktop-released.jsonmarker withreason: "archive"releases the transcript for deletion once the marker is older thancleanupPeriodDays. Most people would read "archive" as "keep, but out of the way."What would have saved these, roughly in priority order:
/resume, plus a startup notice listing what the next sweep will remove.unlink. Move expired transcripts to a trash folder with a grace period so a mistake is recoverable.My workaround is
"cleanupPeriodDays": 3650in~/.claude/settings.json. Users shouldn't have to find that setting after the data is already gone.