[BUG] [#40175 extension] Global Instructions silently revert via bidirectional UI↔session CLAUDE.md sync (last-writer-wins)

Resolved 💬 6 comments Opened Apr 15, 2026 by SsuHan-Liu Closed May 26, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code
Update 2026-04-21 — mechanism refined. See 2026-04-21 comment for the current root-cause description. In short: the propagation documented in §§5–6 is driven by a bidirectional UI ↔ session-local CLAUDE.md sync with last-writer-wins (forward at session create, silent reverse overwrite on every user message), not by .claude.json stale-write spreading as §§1/4 originally framed. §§5–6 observations still hold; Dispatch is the longest-lived holder, not the unique mechanism (minimal repro in the 2026-04-21 comment needs no Dispatch). §7's auto-compact propagation hypothesis is no longer required to explain the observed behavior; §10's cleanest fix direction sharpens to asymmetric sync (keep forward, remove or gate reverse). Original report preserved below for reference integrity with the comment chain.

What's Wrong?

1. TL;DR

_[Edit 2026-04-21: framing in this section is superseded — see Update preamble at top.]_

.claude.json stale-write (#40175 / #27941) has a second-order behavior that has not been documented: contamination spreads. Once any single session holds a stale in-memory copy of .claude.json, every session the user subsequently talks to, every session that Dispatch spawns from that contaminated orchestrator, and (under a conjectured auto-compact re-injection path) every session that undergoes an auto-compact while the host file happens to be stale, can become new sources of stale writes.

The practical consequence, reproduced on 2026-04-15 on a Windows 11 MSIX build: a user who edits Global Instructions in Settings, sees the edit persist briefly, and then finds it silently reverted — not once but repeatedly over days — because the set of stale writers keeps growing rather than shrinking.

This is not a new root cause. The stale-write race is the same one documented in #40175. But the propagation pattern means the blast radius is larger than the existing issues suggest, and a fix that targets only the stale-write telemetry without addressing Dispatch permanence or auto-compact behavior will leave the spreading intact.

2. Context and prior art

Two closed/open issues already establish the core race:

  • #40175 tengu_config_stale_write — Cowork Global Instructions silently revert. Most recent comment 2026-04-14 (user ed-ovando) reports a two-week pattern of edits being rolled back. The issue as written describes the mechanism as a single-writer-loses race.
  • #27941 — twin stale-write issue against .claude.json, closed as stale.

Neither issue discusses (a) what makes the race trigger permanently rather than intermittently, (b) how one contaminated session causes additional sessions to become contaminated, or (c) what happens when an auto-compact coincides with a stale host file.

Related but orthogonal issues:

  • #24460 — request that /compact re-inject CLAUDE.md from disk. Closed NOT_PLANNED 2026-03-11. The close comment does not specify whether re-injection already happens from disk or from a frozen in-memory snapshot.
  • #21925 [DESIGN FLAW] Context compaction destroys workflow — no CLAUDE.md reload — asserts the opposite: that post-compact sessions do not reload CLAUDE.md.
  • #45937 — Dispatch main conversation permanently offline with no UI to start a fresh thread.
  • #40070 — Dispatch session collisions; author states "server-side bug, no client-side workaround fully resolves it."
  • #37713 — Dispatch isolation caused by stale session directories.
  • #37473 — Dispatch spawn failures (related).
  • #25579, #26073, #40177, #43534 — Windows-specific MSIX path / VM lifecycle issues that change the surface on which the above mechanisms operate.

The observations in this issue sit at the intersection of the above. They are derivable by reading five issues in parallel; they are not in any single issue.

3. Environment

  • OS: Windows 11 (MSIX package install of Claude Desktop + Cowork mode)
  • Host config path: %LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\.claude.json (note: directly under Roaming\, not Roaming\Claude\; per #25579 the documented path is wrong for MSIX)
  • VM: VirtioFS mount exposing a Cowork-managed CLAUDE.md file as /mnt/.claude/CLAUDE.md inside each session VM. Under current architecture CLAUDE.md is a separate on-disk file from .claude.json — the two are distinct files, not inline within a single JSON. Direct measurement (2026-04-17, this author) shows a per-session mirror at %LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\local-agent-mode-sessions\local_<GUID>\.claude\CLAUDE.md whose mtime tracks host CLAUDE.md writes within the same second; whether the VM mount reads the host file directly or the per-session mirror is not directly determined by the observations in this report
  • Build: Claude 1.2581.0 (f10398, 2026-04-14T17:16:40Z)
  • Date reproduced: 2026-04-15
  • Dispatch in use: yes, first spawned 2026-03-18, continuously alive since

4. The virus analogy (why "propagation" is the right frame)

_[Edit 2026-04-21: framing in this section is superseded — see Update preamble at top.]_

Existing discussion treats the stale-write race as a collision — two writers, last one wins, user's edit loses. A collision is a one-shot event.

What the user actually observes is not a collision but a spread:

  • Day 0: user edits Global Instructions → saved successfully.
  • Day 0 + hours: Dispatch flushes its stale in-memory copy → host reverts to old version.
  • Day 0 + more hours: a second session, which had started with a clean copy, undergoes auto-compact. If auto-compact re-reads CLAUDE.md from the now-stale host file (hypothesis — see §7), this second session is now holding the stale copy too.
  • Day 0 + more hours: user starts a new session today. That session's VirtioFS snapshot reads the host-side stale file at launch → VM sees stale content → any further flush from this session also writes stale. The new session is contaminated before the user has typed anything.
  • Day N: the set of sessions that could overwrite the host with stale content has grown. Some were born contaminated (started after the host went stale), some became contaminated mid-life (auto-compact + Layer 5), some are the original contaminator (Dispatch). The user's correct edit in Settings now has to win against all of them simultaneously.

Calling this a "virus" is not rhetorical flourish — the topology matches: a single carrier, a propagation mechanism (Dispatch persistence, cache-at-launch, and conjectured auto-compact re-read), and a growing population of carriers. A fix targeting the write-path race only (e.g., abort-on-stale instead of warn-on-stale) patches the collision; it does not change the fact that the population of stale holders is non-decreasing over time.

5. Observation 1: Dispatch is a permanent trigger, not an intermittent one

#40175 states stale-writes become "more reliably reproduced when multiple Cowork threads/sessions exist, as each holds its own stale copy." What the existing issue does not say: Dispatch is a session that cannot be ended from the client.

Supporting evidence, all already on file:

  • Anthropic's own help doc (support.claude.com/articles/13947068) states: "There's no way to start a new thread or manage multiple threads."
  • #45937 — main Dispatch conversation gets permanently stuck offline, no recovery UI.
  • #40070 — server-side local_ditto_* parent session ID tied to org ID; survives reinstall. Quote: "This is a server-side bug — no client-side workaround fully resolves it."
  • #37713 / #37473 — Dispatch spawn paths hold stale session directories.

Combined with #40175's stale-write mechanism, this means:

Once a user has opened Dispatch even once, their Global Instructions cannot be reliably edited through Settings UI anymore, because Dispatch's in-memory copy (frozen at the session's first launch date) will eventually flush and overwrite whatever the user just saved. Dispatch is the stale writer that never dies.

This is not present as a standalone ticket in any of #40175, #40070, #45937, #37713, #37473. Each of the five provides one piece of the chain.

Concrete measurements (user-reproduced 2026-04-15):

| Session | Launched | VirtioFS view of /mnt/.claude/CLAUDE.md | mtime observed |
|---------------------------------|----------------|-------------------------------------------|----------------|
| Dispatch (persistent) | 2026-03-18 | 7 lines / 651 bytes | 3/18 10:38 |
| Local session local_53be7a6d | ~2026-04-14 pm | 98 lines / 22,536 bytes | 4/14 23:41 |

Both VMs were reading the same Windows host file via VirtioFS at the same wall-clock moment. They saw different content because each held its own startup snapshot.

6. Observation 2: conversation across sessions re-triggers host overwrite (directly reproduced 2026-04-15)

This is the observation that elevates the bug from "stale writer exists" to "stale writers multiply."

On 2026-04-15 the user had already:

  1. Recovered the 98-line version of Global Instructions from a late-launched session's frozen VM view.
  2. Pasted that 98-line version into Settings UI. Edit persisted, verified via Settings reload.
  3. Then conversed with (a) a Dispatch session that was still running from 3/18, and (b) several sessions that Dispatch had spawned (which inherited Dispatch's stale cache at their launch moment, because the host was stale when they started).

Within minutes of those conversations, /mnt/.claude/CLAUDE.md was again rewritten back to the 7-line version (i.e. host CLAUDE.md content reverted to Dispatch's 3/18 snapshot).

Causal chain:

  • Dispatch holds stale copy A (7 lines, mtime 3/18).
  • Sessions spawned by Dispatch were launched while host was stale → they inherit copy A.
  • User talks to any of these sessions → session's background flush writes A → host overwritten.
  • From the user's perspective: Settings UI edit vanishes again, even though they never opened the original Dispatch tab.

Key point: the user did not need to interact with Dispatch directly. Merely conversing with Dispatch-spawned children — which from the UI look like normal local sessions — was sufficient to re-trigger the overwrite. This explains why #40175 users report that the revert "keeps happening" over weeks despite repeated save attempts.

Equivalently, from a security-engineering framing: the contamination surface is not "Dispatch's tab" but "anything reachable from Dispatch's session graph." The user has no UI cue that a given local session is Dispatch-descended.

7. Observation 3 (hypothesis): auto-compact may be a secondary propagation vector

_[Edit 2026-04-21: this hypothesis is no longer required to explain the observed propagation — see Update preamble at top. The auto-compact / CLAUDE.md-reload question remains a separate open issue.]_
This section is explicitly marked as a hypothesis. The key premise has not been confirmed by Anthropic and the conflicting evidence is documented below.

If premise C below holds, auto-compact turns previously-clean sessions into new stale writers.

Premises:

  1. A (verified): each Cowork session's in-memory copy of .claude.json is frozen at session launch (see §5 evidence table).
  2. B (verified): Dispatch's background flush can overwrite the host file with its stale copy at any moment (§5, §6).
  3. C (not verified by Anthropic): when auto-compact fires inside a session, the system re-reads CLAUDE.md / system prompt content from the host file, replacing the session's in-memory snapshot.

If A and B and C all hold:

  • A session X starts clean (host was correct at X's launch).
  • Mid-conversation, Dispatch flushes → host goes stale.
  • X undergoes auto-compact → X's in-memory copy is updated to host's current (stale) content.
  • X's next background flush writes stale content to host.
  • X is now a contaminator, even though it started clean.

Evidence for and against C:

  • For: morphllm.com/claude-code-auto-compact (community blog) asserts "CLAUDE.md files are re-injected fresh from disk" during compact, but does not cite a source.
  • For: #24460 was closed NOT_PLANNED — the close implicitly frames re-injection from disk as already the behavior, though the comment does not spell this out.
  • Against: #21925 asserts that post-compact sessions do not reload CLAUDE.md at all.
  • Unclear: product-line difference — Claude Code CLI and Cowork may have different compact behaviors. Existing issues don't always specify.

Proposed verification experiment (six steps; any user or Anthropic QA can run):

  1. Ensure Dispatch is terminated; confirm host .claude.json holds known-good version A.
  2. Open a new Cowork session X; confirm X's /mnt/.claude/CLAUDE.md = A.
  3. In the background, launch a second session Y whose startup snapshot is a known-stale version B; allow Y to flush → host now holds B.
  4. In session X, inject sufficient input to trigger auto-compact.
  5. Immediately after compact completes, ask X to print /mnt/.claude/CLAUDE.md.
  6. Result = A → premise C is false, Layer 5 propagation does not exist. Result = B → premise C is true, propagation chain confirmed.

Whichever result obtains should be documented. A = A result is not benign — it would mean post-compact sessions are stuck on stale CLAUDE.md content, which is its own failure mode (the user-visible complaint of #21925).

8. Evidence summary

All observations in §§5–7 reduce to cross-references of existing issues plus one directly-reproduced event:

| Claim | Evidence | Status |
|---------------------------------------------------------|-------------------------------------------------------------|-------------------|
| .claude.json uses stale-write with warn-only abort | #40175, #27941 | Published |
| Session in-memory copy is frozen at launch | Direct measurement 2026-04-15 (§5 table) | Reproduced |
| Dispatch cannot be terminated from client | support.claude.com/articles/13947068, #45937 | Published |
| Dispatch session ID persists server-side across reinstall | #40070 (author quote) | Published |
| "Dispatch = permanent stale-writer" as composite claim | No single issue | Not on file |
| Talking to Dispatch-spawned sessions re-triggers overwrite | User reproduction 2026-04-15 (§6) | Reproduced, novel |
| /compact re-injects CLAUDE.md from disk (premise C) | morphllm blog (unsourced); #24460 close (implicit); #21925 contradicts | Unconfirmed |
| Windows MSIX documented path is wrong | #25579 (NOT_PLANNED) | Published |
| Mechanism linking .claude.json stale-write to host CLAUDE.md revert under current (CLAUDE.md-separated) architecture | Not instrumented | Uncertain |

9. Impact: contamination surface is monotonically non-decreasing

Under current behavior, the set of sessions that could stale-write to host .claude.json at any given moment cannot shrink through user action short of a full Dispatch server-side reset + killing every local session + restart.

Specifically:

  • Every local Cowork session the user opens while the host is stale is born contaminated.
  • If premise C holds, every session that undergoes auto-compact during a stale window becomes contaminated.
  • Dispatch persists, so the window is never fully closed.
  • The PowerShell cleanup in §11 can restore a clean baseline, but any subsequent Dispatch interaction rearms the loop.

From the user's point of view this manifests as: "I fixed my Global Instructions, and a day later they were wrong again. I fixed them again, and a week later they were wrong again." The existing #40175 report frames this as "sometimes my edit is lost." The actual pattern is that the set of potential overwriters is growing, so the fix window keeps closing faster than the user can re-save.

This is why we believe the fix priority for #40175 warrants escalation relative to how it currently reads as a "sometimes" bug. It is an always-bug whose apparent intermittency is an artifact of small session graphs.

10. Suggested directions (non-prescriptive)

Offered as starting points, not as a demand for a specific implementation:

  1. Abort, don't warn, on stale write. saveConfigWithLock already records tengu_config_stale_write telemetry when mtime/size drift is detected; the current behavior is to log and proceed. An abort (with the session re-reading the current host file before retrying) would make the stale-write race self-correcting rather than self-reinforcing.
  2. Surface a Dispatch reset control. #45937 already requests a "start new thread" UI; independently of that, a /reset-dispatch command or Settings toggle that kills the server-side local_ditto_* session would let users exit the propagation loop without the PowerShell gymnastics of §11.
  3. Document auto-compact behavior re: CLAUDE.md re-injection. Whichever of premise C's two possible values is correct, both have user-visible consequences. If re-inject happens, document the staleness risk. If it doesn't, document the CLAUDE.md-reload failure (#21925). The current ambiguity forces users to guess.
  4. Clarify and document the UI-Save → host CLAUDE.md sync path. Under current architecture Global Instructions are already stored in a separate file from .claude.json (see §3 Environment). However, the mechanism by which UI-Settings saves become durable host CLAUDE.md state is not directly instrumented. Direct measurement on 2026-04-17/18 (same author) shows UI-Save writes land in neither host CLAUDE.md nor any of 4 per-session mirrors, and remain absent after a 1-hour OS restart — candidate write targets include .claude.json.backup.<unix_ms>, a Claude Desktop LevelDB / IndexedDB store, an app-memory-only buffer, or server-side sync. Documenting which component mediates UI-Save → host CLAUDE.md (and when the sync fires) would let users reason about why an apparently-saved edit can later revert. Absent this documentation, the .claude.json stale-write propagation chain (§§5–9) cannot be fully separated from an independent Claude-Desktop-app-local stale-write chain that may also be in play

(4) is architectural and slow; (1), (2), (3) are independently shippable and each partially defuses the propagation.

11. Current user workaround (Windows 11 MSIX, administrator PowerShell)

Posted for completeness. This is a workaround, not a fix — it restores a clean baseline but leaves the mechanism intact.

# 0) Stop all Claude processes and the Cowork VM
Stop-Process -Name "Claude" -Force -ErrorAction SilentlyContinue
Stop-Process -Name "Claude Helper*" -Force -ErrorAction SilentlyContinue
Stop-Service -Name "CoworkVMService" -Force -ErrorAction SilentlyContinue
Get-VM | Where-Object { $_.Name -like "*Cowork*" -or $_.Name -like "*Claude*" } |
    Stop-VM -TurnOff -Force -ErrorAction SilentlyContinue

# 1) Dynamically locate the MSIX package directory
$claudePkg = Get-ChildItem "$env:LOCALAPPDATA\Packages\Claude_*" -Directory | Select-Object -First 1
$base = "$($claudePkg.FullName)\LocalCache\Roaming\Claude"

# 2) Back up .claude.json (note: it lives one level above $base)
$claudeJson = "$($claudePkg.FullName)\LocalCache\Roaming\.claude.json"
if (Test-Path $claudeJson) {
    Copy-Item $claudeJson "$claudeJson.backup-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
}

# 3) Clear the server-side Dispatch session remnants (per #45937)
Remove-Item -Recurse -Force "$base\local-agent-mode-sessions" -ErrorAction SilentlyContinue
Remove-Item -Force "$base\bridge-state.json" -ErrorAction SilentlyContinue

# 4) Restart
Start-Service -Name "CoworkVMService"
Start-Process "shell:AppsFolder\$($claudePkg.Name)!App"

Caveats:

  • Must run from an elevated PowerShell (Stop-Service / Stop-VM require it).
  • MSIX virtualization does not apply to PowerShell. Editing %APPDATA%\Claude\ from PowerShell does not redirect; you will modify the wrong location. Use the dynamic $claudePkg.FullName path above. (#25579 documents the path, marked NOT_PLANNED.)
  • Dispatch's old conversation history is stored server-side and is not cleared by this script; newly spawned task sessions will re-read CLAUDE.md correctly once the host file is clean, but historical Dispatch turns retain their original embedded system prompt.

12. Related issues (grouped)

  • Core race condition: #40175, #27941, #40731
  • Compact behavior: #24460, #21925
  • Dispatch lifecycle: #45937, #40070, #37713, #37473
  • Windows-specific surface: #25579, #26073, #40177, #43534

---

Filed as a structured extension of #40175, not a duplicate. If maintainers prefer, §§5–6 (Dispatch permanence + conversational re-triggering) and §7 (auto-compact hypothesis) can be split into two issues; they are presented together here because the causal chain runs through both and readers evaluating the propagation argument benefit from having them adjacent.

What Should Happen?

Global Instructions edited in Settings should persist after Save. Specifically, the content written to .claude.json should not be subsequently overwritten by stale in-memory copies held by background sessions (in particular Dispatch, which cannot be terminated from the client). See §10 of "What's Wrong?" for suggested fix directions.

Error Messages/Logs

No user-visible error. Failure is silent — Global Instructions in Settings UI revert to an older version without any warning, log entry, or notification. This is part of what makes the bug hard to diagnose.

Steps to Reproduce

Full reproduction detailed in §6 of "What's Wrong?" above. Summary:

  1. Have a Dispatch session alive (spawned at any prior date — in our repro, 2026-03-18).
  2. In Settings, edit Global Instructions; Save; verify via Settings reload that the edit persists.
  3. Converse with any Cowork session — especially sessions spawned by Dispatch, which are UI-indistinguishable from local sessions.
  4. Within minutes, re-open Settings: Global Instructions have reverted to a pre-edit version.

Reproduced 2026-04-15 on Claude 1.2581.0 (f10398). Direct measurement evidence (VirtioFS view divergence between two live sessions) in §5 table of "What's Wrong?".

Claude Model

Not sure / Multiple models

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

N/A — this is a Claude Desktop (Cowork mode) bug, not Claude Code CLI. Claude Desktop build: 1.2581.0 (f10398, 2026-04-14T17:16:40Z).

Platform

Other

Operating System

Windows

Terminal/Shell

Other

Additional Information

Template note: this repo's Bug Report template is CLI-oriented (Claude Code Version, Terminal/Shell, Platform=API/Bedrock/Vertex). This report is for Claude Desktop + Cowork mode on Windows MSIX, so several fields are marked N/A or Other. The precedent #40175 is also a Cowork mode bug in this repo. If maintainers prefer a different filing location, happy to re-file — please advise.

View original on GitHub ↗

This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗