Display text leaks into persisted respawnFlags: background agents relaunched with --model "opus[1m]" (ANSI bold fragment)
Environment
- Claude Code 2.1.201 when the corruption was captured; artifacts persist and are reused after updating to 2.1.206
- npm global install under Homebrew node, macOS arm64 (Darwin 25.5.0)
- Background agents: daemon (
claude daemon run --origin transient) +--bg-pty-host+ worker architecture
Bug
Three background-agent jobs ended up with a corrupted model value persisted in ~/.claude/jobs/<id>/state.json:
"respawnFlags": [
"--agent", "claude",
"--permission-mode", "auto",
"--effort", "xhigh",
"--model", "opus[1m]"
]
The stored value is the literal 8 characters opus[1m] (verified with Python repr() — no ESC byte present). [1m is the ANSI SGR bold prefix; the model name appears to have been captured from rendered display text (the CLI renders model names wrapped in ESC[1m…ESC[22m) with the ESC byte stripped, rather than from the raw model id/alias.
Every supervisor respawn then relaunches the worker with the bogus flag, visible in ps:
claude.exe --resume …/<session>.jsonl --agent claude --permission-mode auto --effort xhigh --model opus[1m]
Impact
- Workers start and run anyway (some fallback resolution applies), so sessions may silently run a different model than the user selected.
- The corrupted value is replayed on every respawn. Notably, after updating to 2.1.206, the daemon's post-takeover prewarm respawned one of these jobs and the new worker inherited
--model opus[1m]verbatim from state.json — respawn does not sanitize or re-derive the model.
Context / repro hints
- All three affected jobs were created 2026-07-02 → 07-04 on 2.1.201 via the background-agent dispatch path with
--permission-mode auto(two also with--effort xhigh). Other jobs on the same host captured clean values (opus,fable,claude-opus-4-8), so the contamination is path-dependent rather than universal. - A fresh dispatch on 2.1.206 (attaching and sending a new message) re-captured a clean
claude-opus-4-8— which is how one of the three self-corrected. The other two required hand-editingstate.json. - Possibly related to the resume/respawn family: #73754, #74182, #75986 (the crash-loop itself is fixed as of 2.1.202 — this report is only about the corrupted flag capture/persistence).
Expected
respawnFlags should only ever contain raw model ids/aliases. Display strings should never reach persisted argv, and respawn could defensively reject or normalize values containing control-sequence remnants (e.g. [<n>m).