Measured by the domain:services dev seat while implementing #10547 (PR #10739). Caught before any commit, so nothing shipped — but the same sequence one step later produces a PR carrying four other agents' merged files.
The shape
Worktree isolation covers the working tree and HEAD. It does not cover refs/remotes/*, which live in the common .git directory and are shared by every worktree of the repo.
So while you work, another agent's git fetch advances refs/remotes/origin/main underneath you. The ref you branched from is not the ref that name points at any more, and nothing tells you it moved.
The prescribed-looking recovery then does the damage:
git reset --soft origin/main # ← re-bases onto a NEWER tip than you branched from
Everything merged into main between your branch point and that newer tip is now staged in your index as your change. In the measured instance that was four other agents' merged files. A following git add -A / git commit puts them in your PR under your authorship.
Why it reads as safe
The fix at the recipe level
Reset to the recorded base sha, never to the origin/main ref.
BASE=$(git rev-parse HEAD) # record at branch time, before any work
...
git reset --soft "$BASE" # ✅ a fixed coordinate
git reset --soft origin/main # ⛔ a shared pointer that moves under you
The same reasoning applies to any command taking origin/main as an implicit "where I started": git diff origin/main..., git log origin/main.., git rebase origin/main. They are all reading a ref another agent can move. When the question is "what did I change", the answer must be anchored to a sha you recorded, not to a name someone else can repoint.
This is the third member of one family
Three shared-state hazards are now measured, all with the same signature — an operation that looks local, reaches state shared by every parallel agent, and reports success:
| # | shared state | measured |
|---|
| 1 | refs/stash — one LIFO stack for all worktrees | #5742 (cost two agents their in-flight work) |
| 2 | node_modules hardlinks into the shared pnpm store — an in-place vendor edit corrupts every agent's tree and the store | measured on #10532 (6 hardlinks on one vendor file) |
| 3 | refs/remotes/origin/main — advanced by any agent's fetch | this card |
⚠️ The generalisation worth writing down is not the three instances but the rule they share: git worktree isolates the tree and HEAD, and nothing else in .git. Anything else under .git/ — refs, the stash stack, config, hooks — is common. A recipe is only worktree-safe if it never names shared state.
Related
Filed unassigned for triage. Note that whichever surfaces get the warning (CLAUDE.md, AGENTS.md, the os-dev agent definition, the pm-dispatch skill) are governed surfaces — #7863 is the card recording that fixing only the two documents a human reads leaves the recipe shipping in three other places.
Measured by the
domain:servicesdev seat while implementing #10547 (PR #10739). Caught before any commit, so nothing shipped — but the same sequence one step later produces a PR carrying four other agents' merged files.The shape
Worktree isolation covers the working tree and HEAD. It does not cover
refs/remotes/*, which live in the common.gitdirectory and are shared by every worktree of the repo.So while you work, another agent's
git fetchadvancesrefs/remotes/origin/mainunderneath you. The ref you branched from is not the ref that name points at any more, and nothing tells you it moved.The prescribed-looking recovery then does the damage:
Everything merged into
mainbetween your branch point and that newer tip is now staged in your index as your change. In the measured instance that was four other agents' merged files. A followinggit add -A/git commitputs them in your PR under your authorship.Why it reads as safe
git reset --softis the conservative reset — it keeps the working tree, which is exactly why it gets reached for.origin/mainlooks like a pinned coordinate. It is a moving pointer into shared state, and in a multi-agent container it moves for reasons that have nothing to do with you.git status— the identical symptomgit stashproduces (git stashis repo-GLOBAL across worktrees — two parallel agents popped each other's stashes today; AGENTS.md's worktree discipline never warns about it #5742), and it is missed the same way.The fix at the recipe level
Reset to the recorded base sha, never to the
origin/mainref.The same reasoning applies to any command taking
origin/mainas an implicit "where I started":git diff origin/main...,git log origin/main..,git rebase origin/main. They are all reading a ref another agent can move. When the question is "what did I change", the answer must be anchored to a sha you recorded, not to a name someone else can repoint.This is the third member of one family
Three shared-state hazards are now measured, all with the same signature — an operation that looks local, reaches state shared by every parallel agent, and reports success:
refs/stash— one LIFO stack for all worktreesnode_moduleshardlinks into the shared pnpm store — an in-place vendor edit corrupts every agent's tree and the storerefs/remotes/origin/main— advanced by any agent's fetchgit worktreeisolates the tree and HEAD, and nothing else in.git. Anything else under.git/— refs, the stash stack, config, hooks — is common. A recipe is only worktree-safe if it never names shared state.Related
git stashis repo-GLOBAL across worktrees — two parallel agents popped each other's stashes today; AGENTS.md's worktree discipline never warns about it #5742 —git stashis repo-global across worktrees (the same family, already documented inCLAUDE.md/AGENTS.md)git stashalternative destroys uncommitted work in exactly the situation it is recommended for —git checkout <your-branch> -- <path>is not an undo #7800 / #7800 fixed the two docs a human reads; the same work-destroying recipe still ships in the os-dev agent definition, the stash hook, and the pm-dispatch SKILL #7863 — the stash alternative that also destroyed work, and the surfaces the fix missedgit checkout <ref> -- <path>STAGES the retrieved content — the prescribed reverse-verification workflow can produce a PR that silently reverts its own fix while local tests pass #8280 —git checkout <ref> -- <path>silently stages what it retrieves (adjacent: a git command whose side effect is invisible until commit time)sys_team_membercarries no tenancy fact — a same-org team still routes to a member who holds no membership in the request's organization #10547 / PR fix(approvals): screen expanded team members to the request's organization #10739 — where this was measuredFiled unassigned for triage. Note that whichever surfaces get the warning (
CLAUDE.md,AGENTS.md, theos-devagent definition, thepm-dispatchskill) are governed surfaces — #7863 is the card recording that fixing only the two documents a human reads leaves the recipe shipping in three other places.