Desktop/CLI updates intermittently reset user profile to fresh-install state (settings, theme, session transcripts, permission mode all wiped)
Title
Claude Desktop / Claude Code: updates repeatedly reset user profile to "fresh install" state, wiping settings, session transcripts, and per-conversation permission mode
Summary
On Windows, Claude Code / Claude Desktop updates have repeatedly (3+ times so far, roughly daily) caused the app to behave as if it were a brand-new install: .claude.json gets reset to a bare 8-key bootstrap stub with a new machineID and userID, the Desktop app's config.json reports a fresh first_launch_at, the theme preference reverts to "system", and per-conversation permissionMode resets to "default". Separately and more seriously, the currently-open project's session transcript history (~/.claude/projects/<project>/*.jsonl) was deleted outright during one of these resets, with no backup mechanism to recover it.
Environment
- OS: Windows 11 Pro (10.0.26200)
- Claude Desktop: version 1.19367.0, installed via MSIX / Windows Store (
C:\Program Files\WindowsApps\Claude_1.19367.0.0_x64__...\app\Claude.exe) - Claude Code CLI: two independent copies present on the machine —
- global npm install (
npm install -g @anthropic-ai/claude-code), version 2.1.201 - Desktop-app-bundled copy at
%APPDATA%\Claude\claude-code\2.1.202\claude.exe - Install method recorded in
.claude.json:"installMethod": "global"
What we found (root cause investigation)
1. Broken auto-update leaves the global npm CLI binary missing
.last-update-result.json recorded a "success" update from 2.1.197 → 2.1.201, but the actual bin folder contained only:
bin/claude.exe.old.1783240626972
No bin/claude.exe at all. The updater's rename-old/place-new swap only completed the rename step. Running claude --version afterward failed outright (No such file or directory on claude.exe). Fixed manually via npm install -g @anthropic-ai/claude-code@2.1.201.
2. .claude.json gets reset to a fresh-install stub
Observed the live file shrink from ~39.5KB to 387 bytes, containing only:
{
"firstStartTime": "...",
"machineID": "<DIFFERENT FROM PREVIOUS>",
"opusProMigrationComplete": true,
...
"userID": "<DIFFERENT FROM PREVIOUS>"
}
Both machineID and userID differed from the value in a backup taken minutes earlier (~/.claude/backups/.claude.json.backup.<epoch>, which the app itself writes periodically). This lost: projects (per-project MCP server config), oauthAccount, githubRepoPaths, pluginUsage, skillUsage, cachedGrowthBookFeatures, etc. Recovered manually by copying the most recent valid backup back over .claude.json.
3. Desktop app also treats itself as a first launch
%APPDATA%\Claude\config.json showed:
"first_launch_at": 1783457769509,
"userThemeMode": "system"
first_launch_at was set to a timestamp of the current session, not the actual first install — despite this being a machine the app has run on for weeks. userThemeMode reverted from an explicit "dark" to the default "system", causing the UI to render light/white against this user's dark-mode OS-independent preference.
4. Per-conversation permissionMode also resets
Each conversation's local session-state JSON (%APPDATA%\Claude\local-agent-mode-sessions\<account>\<workspace>\local_<sessionId>.json) contains its own "permissionMode" field, independent of the CLI's ~/.claude/settings.json (permissions.defaultMode). After the reset, new conversations came up with "permissionMode":"default" (manual per-tool approval) even though settings.json has always correctly specified "defaultMode": "bypassPermissions" and was never touched by any of this.
5. Session transcripts deleted with no backup — the serious one
~/.claude/projects/<project-folder>/*.jsonl (one folder per project working directory) holds full conversation transcripts. For the specific project open at the time of one reset, every prior .jsonl transcript file in that folder was deleted, leaving only the transcript for the session that was open at the time. The directory's mtime matched the exact same timestamp as the .claude.json reset. Unlike .claude.json, there is no backup mechanism for these files at all — Recycle Bin had nothing (consistent with a direct fs.unlink, not a user-initiated delete). Other projects' transcript folders on the same machine, not open at the time, were unaffected — suggesting the reset logic clears state scoped to "the currently active project" rather than the whole projects/ tree.
Suspected trigger
Important new data point: this happens on only some updates, not all, and this machine is one of two devices signed into the same Anthropic account. The user runs Claude Desktop on this machine (a always-on server used for orchestration/agent work) and on a separate personal laptop, both logged into the same account (lastKnownAccountUuid stayed constant across every incident tonight — the account itself was never in question). After one reset-and-relogin cycle tonight, this machine's connector list (Gmail/Calendar/Drive/etc.) changed to match what's configured on the laptop, not what had been configured here. Since remote connectors are account-scoped/cloud-stored rather than per-device, that particular symptom is arguably expected behavior, not a bug — but it's a strong hint that some server-side session/account reconciliation between the two concurrently-active devices may be what's actually triggering the "fresh install" fallback, rather than (or in addition to) purely local update mechanics. That would explain why the reset is intermittent and correlates with some updates rather than firing deterministically on every one: it may depend on what the other device (the laptop) happens to be doing — logging in, updating, or opening the app — at a similar time, not solely on what's happening on this machine.
Independently, three local update mechanisms also coexist on this machine and can race or interfere with each other:
- MSIX/Windows Store auto-update of the Desktop app package itself (log:
[updater] MSIX detected: windowsStore=true ... Checking for updates) - The Desktop app's own update check against
https://api.anthropic.com - The Desktop app's management of its bundled CLI copy under
%APPDATA%\Claude\claude-code\<version>\ - (Separately) the global npm package's own self-update mechanism
Given how frequently Anthropic ships releases right now, updates happening multiple times a day seems to be expected — but each one currently carries a real risk of the app misidentifying itself as a fresh install and discarding local state that should persist across updates. Also worth checking: whether having many claude.exe processes running simultaneously (this machine routinely runs several agent sessions at once) causes file-lock contention during the npm CLI's binary-swap step, since Windows can't overwrite a running executable in place.
Recommend investigating both the multi-device/same-account angle and the local update-race angle — the intermittent "only some updates" pattern is more consistent with the former than a deterministic local bug.
Impact
- Settings (theme, permission mode) silently revert, requiring manual per-update fixes.
- MCP server configuration and OAuth session cache wiped from
.claude.json(recoverable only because the app happens to keep periodic backups of that one file). - Conversation history for the active project can be permanently deleted with zero recovery path.
What would help
- Never derive "is this a fresh install" from anything that can legitimately reset (e.g., a corrupted or in-progress config write) — check for the existence of prior state directories/backups before concluding "first launch."
- If
.claude.json(or Desktopconfig.json) is about to be reset to a bootstrap default, first check~/.claude/backups/for a recent valid snapshot and restore from it instead. - Never delete session transcript files as a side effect of a config reset. If reset logic touches
~/.claude/projects/, it should be additive/backup-first, never destructive. - Make the npm-global CLI's binary swap on Windows atomic/verified (confirm the new
claude.exeexists and runs before removing/renaming the old one; roll back the rename if the new binary never lands).
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗