building vodou.

git commit ships the whole index, not the paths you staged

Parallel AI agents in one git worktree share .git/index, so a careful git add still commits another agent's work. How it happened twice, and a private-index fix.

Chad Priest / / 4 min read

On 2026-09-09 an agent session in my repo staged eight paths, all of them in the gateway under MCP-servers/Vodou-Console/, and ran git commit. Git answered 20 files changed. The other twelve belonged to a different agent session working in the same checkout. It had staged 13 files before mine ever touched the index, including a 466-line test fixture and a big chunk of the engine.

It was the second time. On 2026-07-28 a session staged three paths for a lease feature. A parallel session ran git add somewhere between that session’s add and its commit, and the commit swept in a 185-line hunk from the engine’s daemon, four files under MCP-servers/brain/, and scripts/build-server-bundle.sh. Three paths staged, ten files shipped.

Eight paths staged, 20 files changed

My house rule at the time was “stage explicit paths only. Never git add -A.” I was confident it closed the hole, and I was wrong about that for most of a month. The rule fixes one actor’s selection. It does nothing about what the commit reads.

git commit with no arguments does not commit “what I added.” It commits the index, and there is one index per worktree: .git/index. Every agent session in that worktree reads and writes the same file. Your git add mine.txt is one write into a global buffer that other processes are also writing to, and commit snapshots the whole buffer. Being careful about what you add only helps if you are the only one adding.

There were two ways in, and they need different defenses. In the July case a peer wrote during my window, so the exposure was the time between add and commit. In the September case the peer’s work was already staged before we started, so there was no race at all, only a buffer that was dirty from the start.

Any shared staging buffer plus “commit what’s staged” leaks

Here is the general version, with git taken out. Several autonomous workers share an implicit, mutable staging area. Each worker adds its own inputs to it, and the publish step takes a snapshot of the whole area instead of the worker’s declared inputs. You see this in parallel coding agents (Claude Code, Cursor, Aider) sharing one worktree, in CI jobs that share a checkout or a build cache and upload “whatever is in dist/”, and in multi-agent frameworks where every agent writes to one scratchpad directory and a finalizer ships the directory.

A publish operation must read only the inputs its own actor declared, never a buffer that another actor can write to. You can check that against a codebase: find every commit, upload, or flush, and ask what it reads.

Here is the check. It takes two minutes in a scratch directory, then one grep against your own agent tooling:

# Reproduce: two "agents", one index
git init race && cd race && git commit -q --allow-empty -m init
echo theirs > theirs.txt && git add theirs.txt   # agent B, earlier
echo mine   > mine.txt   && git add mine.txt     # agent A, one explicit path
git commit -q -m "A: add mine.txt" && git show --stat --oneline HEAD
# FAIL: both mine.txt and theirs.txt are in A's commit

# The fix, A's side: publish only declared inputs
git reset -q --soft HEAD~1
git commit -q --only mine.txt -m "A: add mine.txt" && git show --stat --oneline HEAD
git diff --cached --name-only    # PASS: theirs.txt is still staged, untouched

# Audit your own agents: any bare commit is reading the shared buffer
grep -rnE 'git commit( -[am]| -m|$)' your-agent-scripts/ | grep -v -- '--only'

If the grep finds bare git commit calls and git worktree list shows one path while you run several agents, you have this bug whether or not it has fired yet. --only is enough when every hunk in your paths is yours, because it commits the working-tree version of those paths. It is not enough when two agents both edited one file. For that case I switched to a private index: export GIT_INDEX_FILE=/tmp/agent-a.index, git read-tree HEAD, git apply --cached for your own hunks, then commit. That session never reads .git/index and never writes it.

Worktree-per-agent is right, and it did not fit this repo

The standard advice, a worktree per agent and the reference table that marks worktrees “Required” for parallel agents, is correct, because each worktree gets its own index. It does not cover the case where the agents are all editing one running system, with one daemon and one set of hot files, and each agent has to see the others’ changes live to test anything. Befall’s guide puts it well: isolation only moves the collision to merge time. And isolation leaks anyway. claude-code#83311 documents worktree-isolated agents committing onto each other’s branches.

Why Next’s write-up calls HEAD “everyone’s global variable,” and that’s true. The index is the quieter global. When a branch changes under you, git status shows it. When your index gets polluted, nothing looks different until the commit lands, and after a private-index commit, git status goes stale and reports deletions of files that HEAD already has. Before you believe it, check git cat-file -e HEAD:path.

The rule I now apply to any system with more than one writer: before you publish, look at what the publish step reads, not at what you added. If another actor can write to that buffer, your care about your own inputs doesn’t protect the commit.