Preventing File Conflicts When Running Multiple AI Coding Agents
Preventing File Conflicts When Running Multiple AI Coding Agents
Running five AI coding agents on the same repository sounds productive until they all edit the same file at the same time. One agent adds a function, another reformats the imports, a third changes the same function signature. The result is merge conflicts, lost changes, and wasted tokens on work that gets thrown away.
This is not a hypothetical problem. Anyone running parallel Claude Code sessions on a single codebase has hit it.
What Actually Happens Without Isolation
AI agents do not coordinate with each other by default. Each one reads a file, plans changes, and writes the result. If another agent modifies the same file between the read and write, one agent's changes get silently overwritten. There is no lock, no merge, no warning - just the last-writer-wins outcome.
The failure mode is subtle. You see the task marked complete by both agents, but when you look at the code only one agent's work survived. The other spent real compute budget producing changes that evaporated.
Git Worktrees - The Standard Solution
Git worktrees give each agent its own working directory with its own checkout of the repository. Agent A works in project-worktree-a/, Agent B works in project-worktree-b/. They share the same git history but their file systems are fully isolated.
Claude Code now supports worktrees natively. The --worktree flag creates an isolated working directory and starts Claude in it:
# Create worktrees for each agent
git worktree add ../project-feature-auth -b feature/auth
git worktree add ../project-feature-ui -b feature/ui
git worktree add ../project-feature-api -b feature/api
# Start Claude Code in each worktree
cd ../project-feature-auth && claude --worktree .
cd ../project-feature-ui && claude --worktree .
cd ../project-feature-api && claude --worktree .
Each agent commits to its own branch. Merging happens after the work is done, when you can review conflicts deliberately instead of having them silently resolved by whichever agent happened to write last.
The open-source tool clash extends this pattern with early conflict detection - it scans all active worktrees and flags files that multiple agents are about to touch before they start writing.
Task Partitioning
The simplest conflict prevention is assigning agents non-overlapping tasks. This requires upfront planning but eliminates the conflict problem entirely for well-scoped work.
A practical partitioning by file ownership looks like this:
Agent 1 - owns: src/api/, tests/api/
Agent 2 - owns: src/ui/components/, src/ui/pages/
Agent 3 - owns: src/auth/, tests/auth/
Agent 4 - owns: src/db/, migrations/
Agent 5 - owns: docs/, scripts/
Write this down in a AGENT_OWNERSHIP.md file at the repo root and include it in each agent's context. Agents that know their ownership boundaries will respect them - they will ask before touching files outside their zone.
The most common mistake is assigning tasks that sound separate but share files. "Add authentication" and "update the user profile page" both touch user-related models. Audit the file overlap before assigning.
File-Level Lock Conventions
When worktrees are not practical - maybe you are working in a shared dev environment, or the app has state that cannot be cleanly split - lightweight conventions reduce collisions.
A simple lock file approach:
# scripts/agent_lock.py
import json
import os
import time
LOCK_FILE = ".agent_locks.json"
def claim_files(agent_id: str, files: list[str]) -> bool:
"""Returns True if claim succeeded, False if any file is locked."""
locks = load_locks()
now = time.time()
# Release stale locks (agent crashed without releasing)
locks = {k: v for k, v in locks.items()
if now - v["timestamp"] < 300} # 5 minute TTL
conflicts = [f for f in files if f in locks and locks[f]["agent"] != agent_id]
if conflicts:
print(f"Lock conflict on: {conflicts}")
return False
for f in files:
locks[f] = {"agent": agent_id, "timestamp": now}
save_locks(locks)
return True
def release_files(agent_id: str, files: list[str]):
locks = load_locks()
for f in files:
if locks.get(f, {}).get("agent") == agent_id:
del locks[f]
save_locks(locks)
This is not a substitute for worktrees on large projects, but it works well for teams running two or three agents on focused tasks.
The Coordinator Pattern
For larger agent teams, introduce a coordinator agent whose only job is assigning work. It maintains the task queue, tracks file ownership, and assigns new work only when no ownership conflicts exist.
The coordinator's prompt includes the current ownership state:
You are a coordinator agent. Current file assignments:
- Agent 1: working on src/api/users.ts (claimed 8 min ago)
- Agent 2: working on src/ui/dashboard.tsx (claimed 12 min ago)
- Agent 3: idle
New task: "Add pagination to the user list API and update the dashboard to use it"
This task touches src/api/users.ts (owned by Agent 1) and
src/ui/dashboard.tsx (owned by Agent 2). Assign to Agent 1 and
Agent 2 as sequential subtasks, or wait until both are free and
assign to Agent 3 as a combined task.
The coordinator adds a small overhead but prevents the silent conflict problem completely.
Handling Shared Files
Some files are inherently shared - package.json, global type definitions, shared utilities. These need special handling:
Option 1 - Freeze shared files. Mark them as read-only for agents. Changes to package.json happen in a dedicated "dependency update" pass, not in feature branches.
Option 2 - Deferred updates. Agents that need to add dependencies flag the request in a separate file (PENDING_DEPS.json). A human or coordinator agent applies all pending dependency updates in a single pass.
Option 3 - Merge-friendly edits. Train agents to make minimal, isolated changes to shared files. Add only what the task needs. Do not reformat or reorganize shared files while making functional changes.
How Much Does This Matter?
In practice, uncoordinated agents on a medium-sized codebase (50,000 to 200,000 lines) hit meaningful conflicts roughly once every 5 to 10 agent-task pairs. That is not rare - it is a regular cost.
With worktree isolation per agent, conflicts drop to near zero during execution. Merge-time conflicts still happen but they are intentional, visible, and resolvable.
The key insight is that multi-agent productivity is not about running more agents. It is about running agents that do not interfere with each other. Five agents with good isolation outperform ten agents stepping on each other.
Fazm is an open source macOS AI agent. Open source on GitHub.