settings.json read-modify-write race: /model save in one session clobbers another session's /effort save
Summary
With two Claude Code processes running, a /model save in one session appears to rewrite ~/.claude/settings.json from the settings that process loaded at startup, silently reverting an effortLevel another session had saved in the meantime. Result: the file no longer reflects any user intent, and — on 2.1.211, where transcripts carried no effort field — the effort a subsequent long automated run actually executed at was unrecoverable from any config source.
Environment
macOS (Darwin 24.6.0), Claude Code 2.1.211, two concurrent terminal sessions.
What happened (2026-07-16, reconstructed forensically)
- Session A: user ran
/effort medium; the session confirmed it was saved as the default, andsettings.jsonthen carried"effortLevel": "medium". - Session B (a separate Claude Code process, started earlier while the default was
xhigh): user ran/modeland saved. settings.jsonafterwards read"effortLevel": "xhigh"— session B evidently wrote the whole settings object from its stale in-memory copy, reverting session A’s save (file-change timing puts the revert at session B’s/modelsave, 09:07 HST).- A ~2-hour automated run then executed with the file claiming
xhighwhile the session-inherited effort was actuallymedium. Which one had really applied had to be settled statistically from the transcripts (thinking-block frequency ~51% of messages ≈ the medium signature, vs 80–100% for xhigh on the same CC version) — about an hour of forensics for something a config file should answer.
This was not reproduced in isolation (the sequence above is inferred from file state, save timing, and session records), but the write-whole-object-from-stale-memory mechanism fits all observations.
Ask
Make settings saves read-modify-write against fresh file contents (re-read + merge the changed key, or take a file lock) so concurrent sessions cannot silently revert each other’s saves.
The recovery half of this incident is already addressed: 2.1.212’s “session transcripts record the reasoning effort level on each assistant message” makes the executed effort recoverable ground truth going forward — thank you. The race itself remains, and it still corrupts the _default_ that the next session will inherit.