Concurrent agent mutation: parallel agents corrupt shared state (settings.json, git staging, tmux)
Bug Category
Concurrent mutation / race conditions is the #3 bug category (~6 issues). When multiple agents run in parallel via the Task tool, they corrupt shared mutable state.
Representative issues
- Parallel agents corrupt settings.json (#29917) — multiple subprocesses read-modify-write the same JSON file concurrently, producing malformed JSON
- Agent cleanup kills its own tmux session (#29787) — non-deterministic process teardown races with the agent's own session
- Permission responses lost on client switch (#29863) — stale permission prompts queued across turns when clients switch
- Hook deduplication drops entries (#29724) — concurrent plugin hook registration loses entries
Root cause
These are classic TOCTOU (time-of-check-time-of-use) races. The pattern:
- Agent A reads shared state (settings.json, git index, process table)
- Agent B reads the same state
- Agent A writes its modification
- Agent B writes its modification, clobbering A's changes
Proposed mitigations
1. Atomic file writes for shared config:
Write to a temp file in the same directory, then rename() (atomic on POSIX). This is a one-line fix for settings.json corruption.
2. File-level advisory locking for settings:
Use flock() around read-modify-write cycles on shared config files.
3. Per-agent isolated config:
Give each parallel agent a read-only snapshot of settings at spawn time. Agent-specific grants accumulate in a per-agent overlay. Merge on agent completion.
4. TLA+ modeling:
The existing SessionLifecycle.tla spec models cascading cancellation but not parallel agent config mutation. Extending it to model concurrent read-modify-write on shared state would catch these races at design time.
Why this matters
Config corruption is silently destructive — the user doesn't notice until Claude Code reports the file is corrupted and refuses to start. Recovery requires manual intervention.
Related issues
#29917, #29787, #29863, #29724
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗