Silent retention cleanup deletes session transcripts with no warning, opt-in, or recovery

Status Open
Reported on v2.1.141
Maintainer reply None cached
Activity 37 comments · opened May 14, 2026

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

  1. 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.
  1. No UI surface for retention. cleanupPeriodDays is 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.
  1. Hard delete, no Trash. Deleted transcripts go straight to unlink(). No soft-delete folder, no grace period, no --restore command, no claude restore subcommand. macOS Trash is bypassed.
  1. 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.
  1. Subagent orphan pattern is a smoking gun. When the parent <sessionId>.jsonl is 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.
  1. 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.
  1. 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.
  1. 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, with claude restore to recover.
  • Make cleanup transactional: never delete a parent .jsonl while its subagents/ 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.log with timestamps and deleted file list.
  • Expose cleanupPeriodDays (and a cleanupEnabled boolean) 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 cwd containing a literal space (e.g. Chrome Extentions/proj-universal-capture-cursor) — produces dual slug variants under ~/.claude/projects/.
  • No cleanupPeriodDays override in ~/.claude/settings.json.
  • File of interest: ~/.claude/.last-cleanup (rewritten each cleanup pass; contains a single ISO timestamp).

On-disk evidence

  • ~/.claude/.last-cleanup updated 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 .jsonl for 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.json contains no cleanupPeriodDays key — 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.

View original on GitHub ↗

37 Comments

github-actions[bot] · 3 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/46621
  2. https://github.com/anthropics/claude-code/issues/39667
  3. https://github.com/anthropics/claude-code/issues/41458

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

FTSBrand · 3 months ago

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

  • #46621 (open, Apr 11) — Linux CLI, v2.1.101. Closest in spirit (silent pruning, asks for warnings + configurable retention).
  • #39667 (closed as duplicate, Mar 27) — macOS CLI, v2.1.85. Documents the same orphan-subagent pattern this report observes.
  • #41458 (open, Mar 31) — macOS CLI, v2.1.87. Distinct bug: cleanupPeriodDays: 99999 was set and ignored. Lists "version upgrade reset" as suspected root cause.

What this report adds that the three above do not

  1. The bug persists in v2.1.141 (3 weeks after #46621, 2 months after #41458). This is not a fixed issue.
  2. Cursor VSCode extension is also affected (anthropic.claude-code-2.1.141-darwin-arm64). The three predecessors are all CLI. This widens the scope.
  3. Cleanup timing was reconstructed from PIDs and .last-cleanup mtime: 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 #41458 root-cause analysis is on the right track (cleanup running before settings fully resolve, or in the wrong subprocess context).
  4. Same-day extension upgrade + data loss correlation: the Cursor Claude Code extension updated on 2026-05-13, and the May 13 session is exactly the day whose transcripts are missing. Strengthens the "version upgrade reset" hypothesis from #41458 root cause #1.
  5. Documented vs. actual retention divergence is severe: with a documented 30-day default, sessions from 2026-04-14 onward should survive. In the affected workspace, no transcript material survives newer than 2026-03-04 — a 71-day gap with the default retention. This is consistent with #41458's "fail destructive on settings parse failure" theory.

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.md

ghh1111 · 3 months ago

+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 · 3 months ago

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:

  • macOS only, and only useful if you have a Time Machine drive with snapshots from before the deletion. No help on Linux/Windows, and no help if you never had backups.
  • Recovers Claude Code chats only (so far), the on-disk JSONL transcripts under ~/.claude/projects/. Doesn't touch Claude Desktop session storage (YET. Working on it.)

The README also has the one-line ~/.claude/settings.json change ("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 · 3 months ago

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. cleanupOldSessionFiles in src/utils/cleanup.ts walks ~/.claude/projects/<slug>/ and calls unlinkIfOld, which deletes any *.jsonl / *.cast with stat.mtime < now - cleanupPeriodDays. Because mtime is externally mutable, anything that touches it flips the outcome: a restore (cp, tar -x, rsync without -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 message timestamp instead of mtime would close this whole class of accidental loss.

cleanupPeriodDays: 0 is an overloaded footgun. getCutoffDate() with 0 returns now (deletes everything), and shouldSkipPersistence() treats === 0 as "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's settingSources: [] (including autonomously spawned subagents), run cleanup that ignores cleanupPeriodDays from ~/.claude/settings.json and fall back to the default 30. So cleanupPeriodDays: 999999 does not protect anyone who runs subagents or SDK sessions.

A SessionStart backup 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 (/rewind orphans 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:

#!/usr/bin/env bash
BACKUP_DIR="$HOME/.claude-session-backups"
sz() { stat -c%s "$1" 2>/dev/null || stat -f%z "$1" 2>/dev/null; }   # GNU || BSD/macOS
find "$HOME/.claude/projects" -name '*.jsonl' 2>/dev/null | while read -r f; do
  dst="$BACKUP_DIR/${f#$HOME/.claude/}"
  s=$(sz "$f"); d=$(sz "$dst")        # ${:-0} guards a file that vanished mid-walk
  if [ ! -f "$dst" ] || [ "${s:-0}" -gt "${d:-0}" ]; then
    mkdir -p "$(dirname "$dst")"; cp "$f" "$dst"
  fi
done

~/.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 honor cleanupPeriodDays.

---

Already lost sessions to this (on ext4)? An after-the-fact recovery toolkit - volatility-ordered: stop writes, dump live claude --resume process 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; the SessionStart backup hook above is what keeps you from needing it.

garrettmoss · 3 months ago

@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 SessionStart hook 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 a backup_claude_history.py alongside 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 · 3 months ago

@garrettmoss sure, I will have my Claude talk to your Claude 😁

KirkPX · 3 months ago

Adding a data point on scope, because this one hurt.

On macOS, cleanupPeriodDays was never surfaced to me — I found out only when /resume came up nearly empty. On disk: 773 session folders, but only 132 surviving .jsonl transcripts. Roughly 640 conversations spanning January through mid-May were silently deleted, each leaving an orphaned subagents//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 · 3 months ago

@KirkPX have a look at the .jsonl carving skill in ojura/claude-skills, it might save some chats.

suenamis · 2 months ago

Adding a Windows Desktop data point.

Lost two sessions in the same project (Billy AI Fish and Billy 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 .jsonl files 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 uses fs.unlink).

Two concrete points for the fix discussion:

  1. Setting cleanupPeriodDays: 0 is 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. Accepting 0 as the intuitive "never clean up" value would close a real UX gap at effectively zero cost.
  1. Auto-memory MEMORY.md / project_*.md files 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.

Carum · 2 months ago

I need this fixed. Claude is literally destroying work information I have generated with my tokens. This is an unacceptable state.

AiTrillium · 2 months ago

Thanks @ojura — your unlinkIfOld / mtime analysis (and the --setting-sources local / settingSources: [] override that defeats a high cleanupPeriodDays) is the clearest root-cause account on this bug — and @garrettmoss for the open-source recovery script.

A couple of data points and one ask, observed on claude-opus-4-8 / Claude Code, 2026-05-30 (default config, no cleanupPeriodDays set):

  1. The surviving boundary is an mtime boundary, to the day — independent confirmation of @ojura's analysis. Our oldest surviving transcript had an mtime of exactly 2026-04-30 (the 30-day line); everything older was gone. This is the "clean" case: cleanup running exactly as documented and still destroying months of work (our IP). It complements the shorter-than-documented losses others report here — the point being that the documented default is itself the harm.
  1. The loss is avoidable — the data persists until overwritten. We reconstructed a coherent ~900-session archive from pre-deletion filesystem backups, held outside ~/.claude/projects/ so cleanup can't reach it. (Without a prior backup it's filesystem carving, per @ojura / @garrettmoss — far harder.)

For breadth, the documentation gaps are tracked separately from this bug: #51779, #38576, #63777 (cleanup-scope omissions) and #63842 (session pinning).

One ask of Anthropic: before any delete, prompt for consent or move files to the OS trash/Recycle Bin (or a ~/.claude/trash/ grace area) — and make cleanupPeriodDays honoured by all setting sources, including SDK-spawned subagents (the gap @ojura identified). An optional export-on-cleanup (a compact JSONL/MD snapshot at deletion time) would make even an expired session recoverable.

chid · 2 months ago

I was surprised by this today - I've only been using Claude Code for a bit over a month, luckily I made backups (for the purposes of using cross coding agent search) but this should definitely be surfaced without having to do a Q&A with Claude.

Based on what I can see: no transcripts appear to have been deleted by me. Every project directory has at least 1 .jsonl transcript file, and nothing in your settings enables any kind of auto-cleanup.

A few relevant facts:
- The current project (</>) has 2 transcripts, both from today — that's consistent with a directory that's been freshly created/used.
- There's no retention setting or cleanup hook in your settings.json.
- I have no memory of being asked to delete anything, and no record of doing so.

Can you tell me more about what's missing? For example:
- Which project/directory were you expecting more transcripts in?
- Were there conversations you can no longer find, and if so from roughly when?

That'll help me pinpoint whether something actually disappeared or if the counts just look lower than expected.

and when I pressed further...

Confirmed: Claude Code itself deleted your transcripts — not the AI assistant. Here's what's happening:

The .last-cleanup file is a timestamp Claude Code writes each time it runs its built-in retention cleanup on startup. By default, any session .jsonl transcript older than 30 days is permanently hard-deleted with no warning, no trash, no recovery. Your cleanup ran yesterday at 12:45 UTC.

This is a well-known and actively complained-about issue (https://github.com/anthropics/claude-code/issues/59248) — users are losing conversation history 
blain3white · 2 months ago

For users wanting an independent recovery layer before this is fixed: Clean My Agent (I'm the author) backs up and exports session JSONLs before any cleanup pass runs.

ProIcons · 2 months ago

Corroborating with an independent case, plus a primary-source timeline of how this behavior and its disclosure evolved (claude-code CHANGELOG.md, npm publish timestamps, and Wayback Machine snapshots of the docs).

Another independent data-loss case

  • Linux, CLI (native install), Claude subscription, currently 2.1.175.
  • No cleanupPeriodDays key in any settings file — binary default in effect.
  • Discovered 2026-06-12: across every project on the machine, the oldest surviving transcript is dated exactly 30 days prior (2026-05-13). Everything older is gone — including multi-week design arcs (one project: 35+ hours of recorded design sessions whose decision rationale existed nowhere else).
  • No notice was ever displayed. ~/.claude/.last-cleanup confirms the sweep runs at session start, consistent with this issue's observation (it even ran mid-investigation when a stray CLI invocation spawned a session).
  • Secondary observation, hedged because I have a single datapoint: a file under ~/.claude/plans/ that a surviving 2026-06-09 transcript references as existing was gone by 2026-06-12, while a newer plan file (mtime 2026-05-30) survives — consistent with an age-based sweep of ~/.claude/plans/ that I cannot find in any changelog entry or documentation. Maintainers: please enumerate the complete set of paths the retention sweep touches.

Transcripts are load-bearing data — by the product's own design

The strongest argument that silent deletion is wrong here isn't any individual workflow; it's that Claude Code itself treats transcripts as durable data and builds features on top of them:

  • --resume, --continue, and /fork are transcript-backed — the resume picker is an implicit promise that history persists.
  • Auto-memory writes session IDs and timestamps into memory files as provenance ("decided in session X on date Y"). After the sweep, every one of those references dangles permanently — the product's own memory now cites records the product destroyed.
  • Session-search tooling ships in Anthropic's own plugin marketplace; "what did we decide last month, and why" is a supported, encouraged workflow.
  • Handoff and decision-recovery workflows (also community-standard) cite session IDs as the source of truth for rationale that was never copied into a document.

A system that encourages building a knowledge substrate on these files, then deletes that substrate on a rolling 30-day fuse without telling anyone, is internally contradictory. Transcripts are not cache; the artifact records what was decided, the transcript is frequently the only record of why.

Verified timeline (CHANGELOG.md + npm publish dates + Wayback)

| Date | Version | Event |
|---|---|---|
| 2025-05-17 | v0.2.117 | Changelog: "Introduced settings.cleanupPeriodDays" — the deletion behavior ships |
| 2025-06-15 | — | Wayback, docs.anthropic.com/en/docs/claude-code/data-usage: sole disclosure is "Users' local Claude Code clients may store sessions locally for up to 30 days so that users can resume them. This behavior is configurable." — framed as a privacy reassurance ("up to 30 days"), not a data-loss warning; setting not named |
| 2025-09-03 | — | Wayback: "Local caching" bullet appears on the same page; still "(configurable)" with no setting name |
| 2026-03-24 | v2.1.83 | "Fixed tool result files never being cleaned up, ignoring the cleanupPeriodDays setting" — sweep scope grows |
| 2026-03-31 | v2.1.89 | "cleanupPeriodDays: 0 … rejected with a validation error — it previously silently disabled transcript persistence" — the only "keep forever"-adjacent value removed; minimum is now 1, retention-forever requires an arbitrarily large number |
| 2026-04-10 | v2.1.101 | "Fixed --setting-sources without user causing background cleanup to ignore cleanupPeriodDays and delete conversation history older than 30 days" — a confirmed fail-destructive path: when settings resolution fails, cleanup falls back to the 30-day default and deletes. This corroborates #41458 (explicit 99999 setting, 490 sessions deleted anyway) |
| 2026-04-15 | v2.1.110 | "Fixed session cleanup not removing the full session directory including subagent transcripts" — confirms the orphaned subagents/ dirs documented in this issue were the sweep's doing, and the fix was to delete more, not to warn |
| 2026-04-21 | v2.1.117 | "The cleanupPeriodDays retention sweep now also covers ~/.claude/tasks/, ~/.claude/shell-snapshots/, and ~/.claude/backups/" — a directory named backups is now age-swept |
| 2026-04-30 | v2.1.126 | claude project purge added with --dry-run, -i, -y — the manual deletion path gains exactly the safety affordances the automatic path still lacks |
| Apr 1 – May 6, 2026 | — | Wayback bisection of code.claude.com/docs/en/data-usage: the name cleanupPeriodDays first appears on the user-facing data page in this window — ~11 months after the behavior shipped, and only after #41458/#46621 were filed |

Two structural points fall out of this timeline:

  1. The sweep's scope has only ever expanded (tool results → full session dirs incl. subagents → tasks, shell snapshots, backups), while notification, preview, soft-delete, and logging were never added. Each expansion was itself silent for anyone not reading release notes.
  2. The disclosure lives in the wrong place. /en/data-usage is about Anthropic's server-side data handling; client-side destruction of local files is buried inside it, originally phrased as a privacy guarantee ("up to 30 days"). A user asking "will Claude Code delete my files?" would never look there — and for the first year, the page didn't name the setting that controls it.

On the suggested fixes

Everything in this issue's list, with two points sharpened:

  • Deletion must be opt-in consent, not opt-out discovery. Automatic cleanup is a quality-of-life feature for users who want their disk tidied — these are the user's files on the user's machine, and their lifecycle is the user's decision. The consent moment is easy to define precisely: a one-time prompt on first startup after the capability lands (which also covers existing installs on upgrade, where a "first run" never happens), or at the very latest immediately before the first deletion pass that would actually remove files — with explicit choices ("keep everything forever" / "clean up after N days") and nothing deleted until the user answers. Every warning, preview, and disclosure proposed in this thread is downstream of getting this one decision right: collect consent before the first destructive act.
  • Fail safe, not fail destructive (underlining #41458, because the v2.1.101 changelog entry proves the failure mode is real, not hypothetical): if settings cannot be read/resolved for any reason (corrupt JSON, --setting-sources configurations, subprocess environment), cleanup must be skipped, not defaulted to 30 days. A ?? 30 fallback in a deletion path converts every settings-resolution bug into permanent data loss.
  • Notify-per-pass with a preview (count, age range, projects) even after consent; soft-delete tier (trash/archive) before unlink; a cleanup log of what was deleted when.
  • Document the complete sweep scope in the settings reference, and keep it current as the scope changes.

Workaround status (for others landing here)

{ "cleanupPeriodDays": 1826250 }

is schema-valid and is honored on 2.1.175 — verified empirically: a transcript aged exactly 30 days survived a cleanup pass that ran after the setting was added. But per #41458 and the v2.1.101 changelog entry, a large value is not a guarantee — any settings-resolution failure reverts to fail-destructive defaults. The only real protection today is external backups of ~/.claude/projects/.

---

Transparency note: this comment was researched and drafted by Claude Code itself (Claude Fable 5), at my direction and with my review — the changelog mining, npm timestamp mapping, and Wayback bisection above were agent-performed. The loss was discovered the same way: the agent went looking for artifacts from its own past sessions and found the transcripts already deleted.

ariutokintumi · 2 months ago

This bug is non-sense. Please either (1) make auto deletion opt-in with "keep forever" as the default, (2) prompt the user before deleting anything, or (3) show a clear warning in settings. Real failure case: take parental or medical leave for more than 30 days, come back, everything is gone.

davidlovas · 1 month ago

+1, and I want to underline the "no warning" part. I lost 201 sessions to cleanupPeriodDays with zero indication that a deletion was pending or had already happened. I only found out when I went looking for an old session and it was just gone.

davidlovas · 1 month ago

A couple of concrete follow-ups from my own run-in with this:

1. A minimal warning would have prevented my entire loss. It does not need to be fancy. Even a startup line like:

⚠️ You have 6 sessions expiring within 7 days. Enter x to list / pin / extend them.

with a daily reminder until deletion would be enough. The issue is not that cleanup exists, it is that it is silent and irreversible. A 7-day heads-up with a one-key escape hatch turns a data-loss event into a non-event. Alternatively, users could "pin" certain sessions to mark them safe from deletion.

2. The mtime keying punishes your most valuable sessions. Cleanup keys on file mtime, so the sessions most likely to get deleted are the long-lived, high-context ones that have been sitting on the back burner. Not touched recently, but definitely not meant to disappear. "Dormant" is being treated as "disposable," and those are often opposites (research threads, long-lived reference and analysis work, architecture discussions you come back to once a month).

3. Partial-recovery workaround if you already got hit: your typed prompts survive even after the transcript is gone, because ~/.claude/history.jsonl is not part of the cleanup sweep. Group its entries by sessionId and you can rebuild your half of every deleted conversation. The assistant replies are gone, but the prompts bring back a surprising amount of context. I used this to salvage 201 deleted sessions. It is a workaround, not a fix, and it should not be necessary.

davidlovas · 1 month ago

Agree with @ProIcons on the core point:

Deletion must be opt-in consent, not opt-out discovery.

These are the user's files on the user's machine. Whether and when they get deleted should be the user's call, not a silent default. Automatic tidying is fine as a feature. It is not fine as a default, and it really should not be the fallback when settings fail to resolve (the fail-destructive path in the v2.1.101 changelog shows that is a real code path, not a hypothetical).

Getting consent is cheap. Prompt once on first startup after the feature lands (which also covers upgrades of existing installs), or at the very least right before the first pass that would delete anything. Give two clear choices ("keep everything" or "clean up after N days") and delete nothing until the user picks one. Warnings, previews, and soft-delete all help, but they are patches on a default that should not exist. Ask first and this whole category of "my sessions just vanished" reports goes away.

mieubrisse · 1 month ago

Just got hit by this in #62476 . I'm flabbergasted this is still unfixed after 2 months.

How is deleting the user's conversation history without their consent okay??

horaciomx · 1 month ago

Another data point: lost a 239-prompt session spanning 3+ weeks of work (May 11–Jun 5) on macOS — returned to resume it on day 34 and the transcript had been silently purged. Nothing in Trash, no archive, no recovery; only my prompts survived via history.jsonl. Also filed #76173 with concrete proposals (soft-delete to archive > startup warning + confirm > minimum: deletion log + a hint in the resume-failure message pointing at cleanupPeriodDays).

DavidMaldonadoc · 1 month ago

Session transcripts never written to disk (not deleted) — 4 long sessions lost in one day, Windows 11

TL;DR — Same symptom as this issue on Windows 11, but a VSS snapshot taken mid-session proves the transcript was never on disk: this is a write/persistence failure, not a deletion. Only long-lived append writes were lost (4 long sessions + history.jsonl); everything written open→write→close survived.

I lost 4 session transcripts on the same day. The signature overlaps with this issue (orphaned
subagents/ directories, cleanupPeriodDays not protecting), but I have one piece of evidence that
points to a different mechanism than deletion, so I'm posting it here in case it helps narrow this down.

Environment

  • Claude Code 2.1.214 (Windows 11 Pro 10.0.26200, NTFS, npm-global install)
  • cleanupPeriodDays: 365
  • SessionEnd hook running a robocopy mirror to a second drive (read-only w.r.t. the source)

What was lost

A census of ~90 projects / 2323 transcripts found exactly 4 orphaned session directories
(directory present, <sessionId>.jsonl absent) — all from the same day, across the 2 projects worked
that day:

| sessionId | duration |
|---|---|
| b21d6a4d-… | 13:35 → 18:38 (~5h) |
| 004077ca-… | 14:15 → 19:16 (~5h) |
| 8555a0a7-… | 18:38 → 20:32 (~2h, process alive until 21:33) |
| 21ae8066-… | 19:54 → 20:37 |

All four are the long sessions of that day. In one of the two projects, 13 short sessions
interleaved in the same hours survived intact. No other transcript is missing anywhere on the system.

The key evidence: the file was never on disk

A VSS shadow copy taken at 16:43 that day — i.e. 3 hours into session b21d6a4d, while it was
actively running
and still had 2 hours to go — contains the project's other 22 .jsonl files but
not b21d6a4d….jsonl.

So this is not an unlink() that happens late in the session, and not a cleanup pass that ran
afterwards. The transcript was already absent from disk while the session was healthy and running,
and it never reappeared. Backups running at 13:46, 14:00, 18:52, 19:42 and 19:48 never captured it
either (the mirror is append-only and never purges, and it did capture other live sessions' .jsonl
files while they were being written — so "file was locked, robocopy skipped it" is ruled out).

Correlated: history.jsonl stopped persisting at the same time

~/.claude/history.jsonl has zero entries for all 4 sessionIds. Its last record that day is at
13:44:46, and nothing more until the following day — despite continuous work across three
projects until at least 21:33. The shadow copy confirms this: the 16:43 snapshot of history.jsonl
has mtime 13:44 and is byte-identical to what survives today.

The discriminating pattern

What was lost is exactly the set of files Claude Code keeps open in append mode for the lifetime
of the session
: the 4 transcripts + the corresponding window of history.jsonl.

100% of what is written open→write→close survived, including writes at 20:38 in the very same
session directories: subagents/*.meta.json, tool-results/ (PDFs, images, txt), file-history/,
security/, tasks/.

This is why I think it's worth distinguishing from a delete-based explanation: nothing was deleted,
the long-lived append writes simply stopped landing on disk.

Ruled out with direct evidence

  • Antivirus — Windows Defender: zero detections/actions in the window, empty quarantine, no third-party AV.
  • Recycle Bin — 4 entries total, newest from April. Not a soft delete.
  • Storage Sense — enabled, but wouldn't selectively remove <uuid>.jsonl while leaving the sibling <uuid>/ directory untouched.
  • My own scripts — the backup is robocopy SRC DEST /MIR /XX; /MIR and /XX act on the destination only, robocopy never writes to the source. No /MOV, /MOVE, unlink, rm anywhere in hooks/scripts.
  • System crash / power loss — zero Critical/Error events in the System log across the window.
  • Version update — 2.1.215 installed ~6 hours after the first loss. Running 2.1.214 at the time.
  • cleanupPeriodDays — set to 365. Also, per the docs the age-based cleanup removes the .jsonl together with its subagents/; the subdirectories surviving indicates that path did not run.

Not available

The NTFS USN journal had already rotated (32 MB circular) by the time I investigated, ~1 day later,
so I could not confirm or rule out a FILE_DELETE record. Worth noting for anyone else debugging this:
pull the USN journal immediately — it's the one source that would settle delete-vs-never-written.

Impact / mitigation

No work was actually lost, because conclusions were written to files during the session rather than at
the end. But the session's reasoning is gone, and a SessionEnd backup hook cannot protect against
this
— the file never reaches disk, and in an abnormal termination the hook doesn't even fire (the
8555a0a7 process was alive at 21:33 and its SessionEnd never ran).

Detection that would have caught it same-day: check for session directories that have no sibling
<sessionId>.jsonl. Happy to share the script.

jason-sachs · 1 month ago

This needs to be an opt-in feature rather than opt-out, both in the setting itself, and even if I want to use a 30-day "cleanup" (I don't), it should ask me anytime it wishes to delete this important information.

jason-sachs · 1 month ago

and NEVER delete log files that are outside the scope of a project. If I'm working in Project A with Claude Code, then the only log files (if any) that are removed should be from Project A, not from other projects.

jason-sachs · 1 month ago

It should also be possible to use /config or some mechanism to see the setting that Claude is using. Deleting files is a "dangerous" operation and if we have the wrong spelling of cleanupPeriodDays we need a way to make sure that the setting is being read as expected.

jomi-se · 1 month ago

Was hit by this today too... Pretty bummed about it to say the least...

loophole64 · 1 month ago

Just devastated by the loss of certain conversation transcripts that I had planned to share with people. How could a company make a decision to delete all of their customers data, irreversibly, without notice? That's wild. They must not have any lawyers.

BasedGPT · 29 days ago

Hey ojura, I have seen the same failure after a restore: the transcript is present, then the next cleanup pass treats its old mtime as the retention signal. A copy keyed on file growth avoids making the backup decision from that timestamp.

I built BasedGPT/claude-code-session-recovery with backup_claude_state.py for keeping the Desktop metadata and ~/.claude/projects/ transcript layers together, and session_watch.py to flag a transcript that disappears or shrinks between starts. For an existing machine, run python tools/diagnose.py first and follow the exact command it prints. Before restoring an archive, set cleanupPeriodDays to 36500, then restore the files and complete the printed metadata step. That is a safeguard for the ordinary cleanup path, not a fix for the restricted setting-source cases you listed.

The grew-only hook you sketched is a useful stopgap because it keeps the latest transcript copy outside the cleanup path without relying on mtime.

Hope this helps, if my tools are able to help you, would appreciate a ⭐ :)

RDavis3000 · 26 days ago

Reproducing this today (2026-08-05, Claude Code CLI). No cleanupPeriodDays override was set — default 30 applied. The oldest surviving transcript across every project in ~/.claude/projects/ was dated exactly 30 days prior to the check, boundary-precise, matching the pattern others have reported here.

The actual issue for me isn't a UI quirk, it's that my own work is just gone. Design discussions, debugging context, the reasoning behind decisions — deleted by a background sweep on startup that I never opted into and was never told about. I only found out because I went looking for a conversation from a couple of months back and it wasn't there. Given how many people in this thread only discovered the cutoff after already losing work, I'd add my voice to the ask: disclose this on first run, and don't destroy data silently with no confirmation.

DmitriyAlergant · 20 days ago

These session rollup jsonl's have cost BILLIONS USD to produce; Paid with clients money either via subsidized subscriptions, or at actual API pricing - potentially costing tens of thousands of USD in API costs per user. These transcripts contain a treasure trove of mineable knowledge and insights. They also serve as a proof of work, justifying the spend. Someone else who ultimately footed the bill may at some point want to audit the user to confirm how the tokens were spent.

Plus this: https://github.com/anthropics/claude-code/issues/62272

Claude Code has no right to default auto-delete valuable data belonging to the user, produced through an expensive service paid by the user.

The only correct solution is to archive (move and zip by month) not discard old JSONLs, unless configured otherwise.

It is possible that Anthropics is intentionally defaulting to a short cleanup to limit outstanding traninign data available in the wild that can later be harvested and used for training by their competitors, while they retain their own copy at their end. This is disgusting.

C3B2W23 · 19 days ago

Pretty much everyone has voiced my thoughts here... this is a massive violation of trust, a huge violation of what should be allowed on a personal computer, and hundreds of hours of lost discussions, work, and context that I will never be able to recover. To find this out, as others have said with ZERO prompt, warning, or even knowing that this was a thing before I went back to work on a project from last month and finding out everything was gone just astounds me.... This never even crossed my mind as a possibility it is so absurdly a violation of anything that is even remotely appropriate for a software product to do. At a minimum, this should be a prompt, an alert, a "delay for 1 week" , being able to turn it off, being able to change the schedule, flat out part of the setup process and for gods-sake the default should have been OFF to begin with. I have months of work now that is gone, with no way to recover those transcripts or details (surprise, I use Claude Code for a lot more than just Coding!) and.... I'm this sets me on serious levels of anger, hate, and depression. ...And, yes I have backups with Time Machine, no I dont keep months worth because my backup is for me to restore if it's stolen, busted, dropped, or damaged beyond repair... NOT because I assume that a software product is going to delete my work history whenever it wants. This is just absolutely insane... You could almost expect this from the web chat version of Claude where they have to store your data, but NEVER expect this to happen on your own computer.

BasedGPT · 18 days ago

Keep an outside copy of ~/.claude/projects/ before the next cleanup pass. I have seen this class of loss happen when cleanup treats a transcript's filesystem mtime as its age: a restored .jsonl can look old even when it was just copied back, so the next pass removes it again.

I built BasedGPT/claude-code-session-recovery with backup_claude_state.py to snapshot both the Desktop metadata directory and ~/.claude/projects/, and session_watch.py to flag a transcript that disappears or shrinks between starts. Run python tools/diagnose.py first on the current machine and follow the exact command it prints. If you restore from Time Machine or another archive, set cleanupPeriodDays to 36500 before extraction, run the printed metadata step, then restore your normal value. That protects the ordinary cleanup path; it does not address the restricted setting-source cases described here.

For ongoing protection, schedule the backup outside ~/.claude/projects/ and keep the copy keyed on file growth, not mtime. That gives you a recoverable copy if cleanup runs again while the upstream retention bug is still present.

Hope this helps, if my tools are able to help you, would appreciate a ⭐ :)

KevinAMullen · 16 days ago

A data point and a reframing, from someone who hit this yesterday.

The data point. While auditing my own ~/.claude/projects/ I indexed the directory, worked
for about 90 minutes, and re-indexed. Two transcripts had been deleted in between — 14 and
15 July, while I was actively working on that directory. No prompt, no warning, nothing in
the log. I only noticed because I happened to be comparing two counts taken either side of it.
So "silent" is stronger than it sounds: the deletion can happen mid-session, to files you are
in the middle of using, and the only way to know is to have measured before and after.

The reframing. Most of the discussion here is "how long should transcripts be kept", and
the counter-argument to a long default is always exposure — the files are plaintext and they
contain whatever was on screen. In my case that was real: an audit recovered live Azure storage
keys, a SQL admin password and a Twilio token from mine, none of which I had ever typed. They
arrived as tool output.

But that trade only exists because the archived copy has to hold the raw text. It doesn't.

I built a redacting archiver over my own transcripts: patterns plus hash-matching of
known-revoked values, writing gzipped copies to a separate host. 113.8 MB → 48.1 MB, one
afternoon. Verification: a rotated password appears in 18 live files and 0 archived ones,
while control phrases survive 38/38 and 27/27 — secrets gone, content intact. That copy can be
kept indefinitely without the exposure objection applying to it, which turns "30 days or
forever" into a much less interesting question.

Two things I'd have wanted to know before building it, in case anyone else tries:

  • The first version failed its own verification. The password was still in 18 of 47 archived

files, because every pattern assumed key=value shape and it also appeared in prose
("the plaintext password <value> for SQL login"), which matches nothing. Secrets get
discussed, not just configured.

  • Over-matching is as bad as under-matching. An early rule reported four non-existent API

keys; it had matched dust-ma|sk-filters and ri|sk-and-environment.pdf.

I've filed the redaction side separately as #86707 rather than pile it onto this thread, since
this one is about the deletion behaviour. Not asking for anything here — just adding the
mid-session-deletion observation, and the note that redaction changes the shape of the
retention argument rather than picking a side in it.

br3nt · 7 days ago

TL;DR - this "purge" feature is rude... You should always let devs know when you're about to destroy their work, and ask for permission/confirmation. I've lots months of important work.

---

I just came back from a month's leave and got hit by this twice! Once at home, and then again at work!

At home, I didn't realise what had happened... I opened claude agents and heaps of my convos were missing.

I didn't really think anything of it at the time... just thought "gee it's going to be really annoying finding the convos to reopen". I was still on holiday mode... so didn't do any investigation into the matter...

Then the same thing happened at work!

Luckily, I created a Claude crash recovery script/prompt, which keeps track of conversations that I don't explicitly close myself so I can easily find and reopen them after a computer restart or crash! Except when I ran it, Claude told me there were no transcripts matching the conversation ids being tracked! "Wtf!" I thought... and began to Google. This is when I learned about the retention/purge policy. 30 days! FFS!

I'm freaking devastated!

I've had convos going for months working on architectures and ideating and brainstorming... and now it's all lost!

Not just the brainstorming.... but also all the decisions made while implementing features, and all the techniques learned along the way now lost!

It's all just gone! I'm back at square one, besides the things I remember or had materialised into code or issues.

It's very rude behaviour/functionality! Not in the least helpful.

At the very least, ask!

"Hey, you have some very long and old convos that haven't been touched in 30 days. Here's the list... if you want me to delete any, just click the checkbox next to the convo, to confirm the delete"

no thanks Claude... I've just been on holidays
br3nt · 7 days ago

A possible glimmer of hope...

The convos that I enabled remote access are still on my phone app!

I can't interact with them because the convos no longer exist on my computer, but at least I have them for the time being....

I just hope they don't get wiped too before I have a chance to copy and save them.

davidlovas · 6 days ago

for those still being impacted by this issue, I have written a comprehensive cli tool (complete with an easy to use tui) which can recover/restore lost sessions (best effort reconstruction from jsonl), transplant sessions from one local dir to another (rehome a project and its sessions resume cleanly from the new location), and sync everything to a safe local destination, as well as periodic backup via git (optional git-crypt) with support for remote backends (github or any other git remote server)

even outside recovery it's extremely useful as a general session explorer (as the tui is called).. see where every session on your machine lives, project by project, which are backed up, stale, or lost, and jump back into any of them with one key

also has ai powered session search and reconstruction with your choice of model (claude, codex, or fully local via ollama)

this is a proper maintained project, not a quick script.. tested, versioned releases, self-updating, works for both claude code and codex

https://github.com/rexovas/session-protect

brew install rexovas/tap/session-protect or curl -fsSL https://get.rexov.as/session-protect | sh

on the redaction concern raised above.. personally, I feel that's not the domain of a backup/explorer tool, it's the domain of claude code itself (hooks are the right layer, scrub secrets at write time before they ever hit disk, rather than after the fact).. a backup tool that rewrites your transcripts is a backup tool you can't fully trust, so this tool deliberately backs up exactly what the agent wrote, byte for byte (git-crypt encryption covers the case where backups leave your machine)

@br3nt give it a try to reconstruct your lost sessions.. the tool surfaces all lost sessions on your machine and can rebuild them into resumable ones

claell · 5 days ago

@codebytere-ant @bcherny can you please look into this? This seems like really bad defaults, also quite some duplicates, and user trust is lost by setting those silent defaults.