[Bug] File-change attribution asymmetry between concurrent sessions
Bug Description
Tool-call file-change attribution appears to cross sessions
A Bash call rendered a second result line in the terminal:
⎿ Updated xxx/xxx.md (+5 -5)
The session that displayed it made no Edit/Write/NotebookEdit call at any
point — every call was read-only (cat, sed, grep, sqlite3) plus two CLI
dispatch commands. The model also never received that line: its tool result
contained only the command's JSON stdout. So the user sees a file change
attributed to the agent, the agent has no record of it, and neither side can
resolve it in conversation.
This has recurred many times in one day across multiple concurrent sessions
on the same machine: a modification line appears under one agent's session,
the user asks that agent, the agent denies it.
Repro shape: several concurrent Claude Code sessions on one machine; run a
Bash command that hands off to a background daemon which writes tracked
files; observe an "Updated <path> (+n -m)" line attached to that tool call
while the model's own tool result contains no such line.
Two candidate causes, neither verified:
(a) file-change attribution leaking between concurrent sessions;
(b) correct attribution of a side effect — the daemon invoked by the command
writes a tracked file and it is attributed to the causing call — in which
case the line is accurate AND the agent's denial is accurate, since the
agent itself edited nothing.
Either way the asymmetry is the defect: the user sees evidence the model
cannot see, so the question "did you do that?" is unanswerable.
Environment: macOS (Darwin 27.0.0), Opus 5 (1M context)
Environment Info
- Platform: darwin
- Terminal: tmux
- Version: 2.1.272
- Feedback ID: 7e5af208-d405-49f2-afea-b3c919861e8d
Errors
[]
3 Comments
Same issue, macOS, 2.1.270 through 2.1.280, 6 to 8 concurrent sessions in one repo.
It is your cause (a). The diff is a before/after snapshot of the whole git working tree around the Bash call, with no notion of which process wrote the file, so a concurrent session's write lands under whichever command brackets it.
Workaround:
"bashEditDiffEnabled": falsein~/.claude/settings.json. Removes the rendered line and thebashEditDifffield on the tool result.Still present on 2.1.281 (macOS, tmux, bypassPermissions, several concurrent sessions in one repo). Confirming cause (a) with controlled tests, plus one detail that explains why it looks intermittent: whether a write is caught depends on the shape of the in-flight command, not on who wrote the file.
Every test below: a detached
nohup sh -c "sleep N; echo … > <repo>/probe.txt"writer (not a Claude session) fires while the session runs one foreground Bash command. mtimes confirm each write landed inside the call's window.| In-flight Bash command | Concurrent write |
bashEditDiffon that call ||---|---|---|
|
sleep 8; echo "…$(test -f …)"| new untracked file | none ||
sleep 5; echo …| append to a tracked file | none ||
python3 -c "import time; time.sleep(12)"| new untracked file |changedFiles: [probe]||
python3 -c "import time; time.sleep(45)"| another Claude session'sWritetool creates a file |created: truefor that file |So a pure wait is credited with creating a file it never touched, while an equivalent
sleepisn't snapshotted at all. It looks like some command shapes skip the before/after snapshot and others don't. From the user's side, the phantomUpdated <file>lines therefore appear under some commands and not others, which makes the bug look random.Two real incidents from the same session:
cdto a scratch dir outside the repo, thenclaude -p …) ran from 13:59:14.150Z to 13:59:24.746Z. Meanwhile another session's sub-agent rangit merge --ff-only(13:59:19.654Z → .879Z). The call'sbashEditDifflisted 39changedFiles, identical togit diff --name-onlyof that fast-forward. The UI renderedUpdated docs/…/callmeter.md (+12 -8)under it.grep -n … | grep -v _test | head -20; f=$(ls …); grep -c …, 159 ms, 13:59:38.059Z → .218Z) was credited with another session'sEdit-tool hunk onscripts/test-codex-sync.sh(tool_use at 13:59:38.074Z). So read-only commands aren't reliably skipped either.As reported above, the model never sees any of this. Its tool_result held stdout only, so when the user asked "why did you change callmeter docs?" the agent could only deny, correctly, without being able to explain what the user was looking at.
Side note for anyone reproducing this headless: in 2.1.282
claude -p,bashEditDiffwasnulleven for the session's own Bash write, so the affected session has to be interactive.Workaround confirmed from the comment above:
"bashEditDiffEnabled": false. Suggested fix: attribute only writes from the command's own process tree, or render the line as "changed on disk during this command (writer unknown)" rather thanUpdated, and put the same line in the model's tool_result so both sides see the same evidence.I'm encountering the same. I have two sessions going on, one is changing code, another is investigating some stuff, I see the diffs from the session changing code in the session investigating stuff.