settings.json rewritten with only {env, statusLine} model — drops hooks key (440 captured occurrences)
Summary
Some settings writer in the Claude Code ecosystem repeatedly rewrites ~/.claude/settings.json as a whole-file write containing ONLY its own model of the file — dropping every other top-level key, most damagingly hooks (which silently disables a user's entire hook layer until manually restored).
Environment
- Claude Code 2.1.207, macOS (darwin 23.6.0)
- settings.json normally carries:
hooks(6 events),env,statusLine,model, permissions etc. - statusLine is configured to a local command (claude-hud) via the standard
statusLine.type=commandconfig.
Evidence (1s-interval file watcher, snapshot on every mtime change, 3 days)
440 captured writes lacking the hooks key, in exactly two shapes:
Shape A — 148 bytes, env only (proxy keys, empty values):
{"env": {"HTTP_PROXY": "", "HTTPS_PROXY": "", "http_proxy": "", "https_proxy": "", "NO_PROXY": "", "no_proxy": ""}}
Shape B — 309 bytes, env + statusLine only:
{"statusLine": {"type": "command", "command": "\"/opt/homebrew/bin/node\" \"<home>/.../claude-hud/dist/index.js\""},
"env": {"HTTP_PROXY": "", "HTTPS_PROXY": "", "http_proxy": "", "https_proxy": "", "NO_PROXY": "", "no_proxy": ""}}
Occurrences are spread around the clock (00:19, 02:04, 03:19, 07:19, 15:02, 23:56, …), including while multiple Claude Code sessions run concurrently.
Additional data point: a whole-file write that GAINED a model key (triggered by running /model in another session) PRESERVED hooks — so at least one writer merges correctly; the Shape A/B writer does not.
Impact
Every Shape A/B write silently kills all configured hooks (SessionStart/Stop/PreToolUse/PostToolUse/ConfigChange/InstructionsLoaded) until the user notices. We caught it twice by hand (once after 2 days of silent loss) before instrumenting; the watcher has since auto-restored 440 times.
Attribution uncertainty (stated honestly)
The two shapes look like an internal "managed settings" model (proxy env + statusLine) being serialized wholesale. We cannot tell from outside whether the writer is Claude Code's own settings subsystem (e.g. the statusline/config path) or a concurrent-session state sync — but the write pattern (whole-file replace with only known-to-writer keys, no read-merge-write) is the defect regardless of which component owns it.
Ask
Settings writers should read-merge-write (preserve unknown top-level keys) rather than serialize their own model wholesale — one writer in this install already behaves correctly (the /model path), so the fix pattern exists in-tree.
Repro sketch
- Configure
hooks+ a command statusLine in~/.claude/settings.json. - Run 2+ concurrent Claude Code sessions; watch the file at 1s resolution (
stat -f %mloop, snapshot on change). - Within hours, whole-file writes matching Shape A/B appear with
hooksgone.