Worktree Layout Conventions for Monorepos With Multiple Agents
Filesystem layout, not prompting, determines whether parallel agents corrupt shared code.

When several coding agents work against the same monorepo at once, filesystem layout decides whether their output merges cleanly or corrupts silently, not skill or prompting. Where each agent's worktree sits, how it's named, and what it isolates determines whether parallel agents produce coordinated work or quietly overwrite each other's edits without either one noticing. Most teams get this backwards: they invest in better prompts and more careful agent instructions when the actual fix is structural, sitting one layer below the agent entirely. Prompting is not a substitute for filesystem discipline, and no amount of instruction tuning stops two agents from writing to the same file at the same time.
Four failure modes show up the moment agents share a working directory. The first is the silent overwrite: two agents read the same file, generate independent edits, and write back, and the second write simply wins. Neither agent gets an error. Neither knows the other's work vanished. The second is branch confusion: one agent runs git checkout mid-task, and every other agent working in that same directory now sees a different filesystem state than the one it started with, without being told anything changed. Third is context contamination, where an agent reading the codebase to plan its next move reads another agent's uncommitted, half-finished changes and builds its reasoning on top of code that will never exist in that form. Fourth is git lock contention: concurrent git operations fight over .git/index.lock, and if one agent crashes mid-operation, it leaves a stale lock file that freezes every subsequent git command for every agent until a person manually deletes it.
None of these four raise an exception, and that's what makes them dangerous. An agent doesn't stop and say "this file changed under me." It proceeds, generates output based on a state that no longer exists, and the corruption compounds for several more steps before a human notices something is wrong. Teams have run into a related version of this at the infrastructure level: multiple agents kicking off expensive build or test commands at the same time thrash shared build and test infrastructure, so the fix is an explicit FIFO task queue that serializes expensive operations rather than trusting agents to avoid stepping on each other. Telling agents to "be careful," or hoping they check before writing, does not solve any of these problems. Physical isolation, built into the layout before an agent ever runs, does.
How git worktrees provide isolation without duplicating the repository
A git worktree is a linked checkout of a different branch, in its own directory, that shares the underlying .git object store with the main clone. It is not a second copy of the repository. Treating it as one misses the point entirely. The commit history, the object database, and the refs all stay in one place. What the worktree gives an agent is its own working-directory state and its own git index, separate from every other worktree pointing at the same repo.
That separation enforces a clean mapping: one agent, one worktree, one branch. Conflicts don't vanish under this model, but they get deferred to merge time, where ordinary git tooling is built to detect and resolve them, instead of happening invisibly during active work. An agent editing files inside its own worktree directory physically cannot touch files in another worktree's directory. There's no shared index to contend over, either, so two agents running git commands in separate worktrees at the same time don't compete for the same lock file the way two agents in one directory would.
Worktrees do not isolate everything an agent touches, and this is the gap teams miss most often. The local database, the Docker daemon, cache directories, shared environment variables: none of that is scoped per-worktree by default. That gap gets covered in the next section, because skipping it is exactly how a team ends up with clean git history and a corrupted database anyway.
As for how far the mechanism scales, practitioners have reported running as many as 371 worktrees against a single repository, which says more about git's internal ceiling than about how anyone should actually work. Somewhere between two and four concurrent agents is the range that stays manageable day to day, before coordination overhead starts eating the gains. Reaching for double-digit worktree counts almost always means solving the wrong problem: the bottleneck was never how many worktrees git could hold, it was how many outputs a human could review.
The three physical layout patterns and when each fits
Three layout patterns show up repeatedly in practice, and they are not interchangeable: each one assumes a different thing about who owns the repo root.
The sibling-directory layout is the most common, and it should be the default for most teams. Worktrees live alongside the main clone, usually gathered under a shared prefix like trees/. Mike Welsh's documented monorepo setup is a clean example: main/ holds the main branch, trees/claude2/ tracks feature/update-components, trees/claude3/ tracks feature/refactor-api, trees/claude4/ tracks docs/workflow-guide, and trees/test-tree/ tracks feature/performance-improvements. The prefix groups everything visually in a directory listing, and because the branch name is baked into the directory name, running git worktree list becomes almost redundant for a quick check on what's where. This pattern fits teams running several long-lived parallel tasks where each worktree functions as a full peer environment to the others.
The nested layout puts worktrees under .claude/worktrees/ inside the repo itself, which is what Claude Code's --worktree flag does by default: it creates the worktree at <repo>/.claude/worktrees/<name>, branches off the default remote branch, and names the branch worktree-<name>. One piece of housekeeping is not optional here: .claude/worktrees/ needs to go into .gitignore, or the worktree's contents start showing up as untracked files in the main checkout. The upside is that nothing lives outside the repo root, so tooling and CI that assume everything sits under one directory keep working without modification. The tradeoff is real: nested worktrees can confuse file watchers and build tools that glob the repo root, so check how a given toolchain handles nested directories before adopting this pattern rather than finding out in production.
The third pattern starts from a bare clone. Running git clone --bare produces a root with no working directory of its own, meaning every active checkout, without exception, is a worktree sibling. pnpm's own documentation recommends exactly this pattern for multi-agent development, specifically because each worktree needs its own node_modules. Trust boundaries across worktrees are worth thinking through carefully, particularly around shared stores that multiple agents can write to. This pattern fits Node and pnpm monorepos well, and it fits any team that wants to enforce the idea that there is no "default" working directory, only explicit checkouts. If a team has to pick one pattern and stop debating it, the bare-clone approach is the most honest about what's actually happening on disk: there's no privileged main copy for an agent to accidentally treat as ground truth.
Across all three, naming discipline matters more than which pattern gets picked, and this is where most teams cut corners. A directory named trees/feat-auth/ tells a developer returning to a tmux session six hours later exactly what's inside it; trees/agent3/ tells them nothing. A consistent prefix, whether it's trees/, wt/, or agents/, makes cleanup scripts and listing commands predictable instead of ad hoc. Worktrees don't clean themselves up, either: removal has to be built into the workflow from the start, or the repository accumulates stale checkouts indefinitely.
Dependency and environment isolation inside each worktree
Each worktree gets its own node_modules by default, simply because each is a separate directory on disk. That's a real cost: every new worktree means a fresh install, and disk use climbs with each one. Symlinking node_modules between worktrees is possible, but only when dependencies are provably identical across the branches involved, which is a narrow enough condition that most teams shouldn't build a habit around it.
pnpm softens the disk cost without removing the install requirement. Its content-addressable global store deduplicates package files on disk across every worktree, so even though each worktree still needs its own install step, the actual storage footprint stays far lower than the equivalent setup under npm or yarn.
.env files don't travel automatically between worktrees, since they're typically gitignored for good reason. Someone, or something, has to copy them into each new worktree at setup time, or a repo can adopt a .env.shared file with a symlink pointing to it from each worktree. Either approach works, but pick one and document it. An agent provisioning a new worktree shouldn't be guessing at what environment state it's supposed to have.
Database isolation is the piece nobody's fully solved with worktrees alone, and it's the failure mode most likely to reproduce the silent-overwrite problem from the introduction, just one layer down. What actually happens without it: Agent A runs a migration inside its worktree, Agent B queries the same local database instance mid-migration from a completely different worktree, and Agent B's test suite either fails against a half-migrated schema or, worse, passes against stale data and reports false confidence. Worktrees share the same local database, the same Docker daemon, and the same cache directories on the host machine, so two agents modifying database state at the same time create race conditions that no amount of directory-level isolation prevents. Pairing worktrees with a database branching service, such as Neon or PlanetScale's branch-per-PR feature, offers the most practical answer, giving each worktree a logical database branch that maps directly to its git branch. Port isolation needs the same explicit treatment: each worktree's dev server and test runner should bind to a distinct port, assigned by the worktree setup script rather than left for the agent to figure out at runtime.
The build-cache problem belongs in this same bucket. If several agents can trigger the same expensive build step at once, the fix is coordinating the operation at the infrastructure level, with a queue that serializes those steps, rather than hoping the agents stagger themselves on their own.
Making the monorepo structure legible to agents before layout conventions can help
A monorepo of any real size outgrows what a single agent can infer from reading files alone. Without some structural signal pointing it toward what matters, an agent spends its context budget guessing which files are relevant to the task at hand, and that guessing has a real cost measured in tokens and in wrong turns.
Anthropic's guidance on large codebases, as summarized in dev.to's analysis of it, makes a specific case here: a single giant root-level CLAUDE.md, combined with undirected file reads, fills up the context window and degrades both cost and output quality. Teams that reach for one enormous root file, thinking it centralizes knowledge for the agent, are doing the opposite of what helps: they're building the exact bottleneck Anthropic warns against. The fix is per-directory CLAUDE.md files, explicit read-deny rules, code intelligence tooling, and sparse worktrees that only check out the parts of the repo relevant to the current task.
Monorepo tooling like Nx addresses the same problem from a different angle, by exposing structured project metadata directly through dedicated commands like nx show project. That gives an agent one consistent interface regardless of what language or framework a given project uses. Tagging systems in these tools classify projects into domain areas, things like "shop," "auth," or "shared infrastructure," which hands an agent the same high-level map of the system that a senior engineer carries around in their head. With that map available, an agent can explore top-down: domain first, then the project graph, then the filesystem, rather than scanning cold and hoping to stumble onto the right files.
Repo structure is itself a fact you hand the agent, not an afterthought to bolt on once things feel disorganized. Vague structure burns tokens on guesses. Machine-readable structure lands in a single line the agent can parse and act on immediately.
Dumping a pile of projects into one directory is not the same thing as building a monorepo, no matter how often the two get treated as synonyms. Without enforced API boundaries, an actual dependency graph, and affected-only build and test commands, what you've built is collocation, and it hands agents the size penalty of a large codebase with none of the navigability benefit. A repo is legible to an agent when the agent can infer responsibility from names, locate the right files quickly, see where the boundaries between components actually sit, and verify a change using commands that behave the same way every time.
Agents-as-code: AGENTS.md, CLAUDE.md, and SKILL.md in a worktree layout
AGENTS.md has become the closest thing to a cross-agent standard. It's a plain Markdown file at the repo root that tells an AI coding agent how to build the project, test it, and change it safely. There's no required schema, but most repos that use it cover the same ground: project overview, build and test commands, code style, testing instructions, security notes, and rules for commits and pull requests. It's stewarded by the Agentic AI Foundation at the Linux Foundation, which gives it more staying power than a convention any single vendor invented on its own.
Claude Code is the exception worth flagging: as of August 2026, it still loads CLAUDE.md rather than AGENTS.md. Maintaining both files by hand is how they drift apart within a few months, one gets updated after a build command changes and the other quietly goes stale. The workaround is to point one file at the other, with a first line in CLAUDE.md that imports @AGENTS.md, so there's a single source of truth instead of two files slowly disagreeing with each other. Both formats support nesting, and the file nearest the code being edited wins over one higher up the tree. That means a per-directory CLAUDE.md or AGENTS.md inside a specific service or package can scope instructions tightly to that piece of the codebase, which keeps irrelevant context out of an agent's window when it's working somewhere specific.
SKILL.md addresses a related but distinct problem: portable, reusable capability definitions. A skill is a directory containing a SKILL.md file plus, optionally, scripts, reference material, and other assets. The loading model is progressive: at the start of a session, an agent reads only the skill's name and description from its YAML frontmatter. The full body of the skill loads only once a task actually matches that skill's domain, and any supplementary files inside the skill directory load only when the task needs them specifically. That keeps skill definitions checked into the repo, version-controlled alongside the rest of the worktree configuration, rather than living in a prompt somewhere outside source control where nobody can review changes to it.
Claude Code's sub-agent system extends this same logic to orchestration. Sub-agents are defined at .claude/agents/ for project-level agents or ~/.claude/agents/ for user-level ones, and a project-level agent takes precedence when a name conflicts between the two. A worktree directive in a sub-agent's YAML frontmatter tells the orchestrator to provision a fresh worktree automatically for each parallel sub-agent it spins up, meaning a top-level Claude session can delegate work to several parallel sub-agents, each with its own filesystem isolation, without a person manually running git worktree add for each one. That makes .claude/agents/ itself a layout artifact, and it deserves the same treatment as any other configuration file: checked into the repo, reviewed in pull requests, not generated ad hoc by whoever happens to be working that day.
Nx's configure-ai-agents command pulls several of these threads together at once. It sets up an MCP server for CI, generates CLAUDE.md and AGENTS.md from one shared source, and provides a consistent skill set across Claude Code, Codex, and other compatible agent tools. Every configuration traces back to a single origin point, so whichever agent tool ends up running in a given worktree gets the same capabilities as every other one, regardless of which worktree it happens to be sitting in.
Orchestration patterns that depend on layout being consistent
Once the layout is consistent and predictable, orchestration can be built on top of it, and several patterns already do exactly that.
Intent's three-tier coordinator model separates roles explicitly: a Coordinator fans work out across tasks, worker agents execute in parallel, each inside its own isolated git worktree, and a Verifier Agent checks the results against the original spec before a developer ever looks at it. Every Space in the system creates a dedicated git branch and worktree automatically, so the layout convention gets enforced by the orchestration layer itself rather than left to whatever habits an individual developer happens to have. Merge sequencing, which the Coordinator handles once the Verifier signs off, only works because the worktrees involved have names the Coordinator can reference reliably. Inconsistent naming would break that step immediately.
Simon Willison described a related pattern in October 2025 that he calls scout mode. A scout worktree gets provisioned purely for exploration, with no intention of merging anything it produces. The agent investigates open questions, how many files would a change touch, what would break, how many hours would it take, and it's expected to leave incomplete implementations and failing tests behind when it's done, because the point was never to ship the work. That only functions cleanly if scout worktrees carry a naming convention that sets them apart from worktrees meant for merging, something like a scout/ prefix, so cleanup scripts and human reviewers don't mistake throwaway exploration for a candidate integration.
incident.io built a bash function, w, that takes a project name and a feature name, creates an isolated worktree on a new branch, and optionally spins up a Claude session if claude gets passed as an argument. One session run through that function, at a cost of roughly eight dollars in Claude credits, produced an 18% build time improvement through API generation work that had sat deprioritized for months. The function itself is the interesting part: it encodes the naming and branching convention directly into a single command, so the convention gets enforced by tooling rather than relying on whoever's running it to remember the rules.
None of this scales indefinitely, and pretending otherwise is where a lot of orchestration ambitions go to die. The two-to-four-agent range keeps showing up across teams as the point where coordination stays manageable; past that, the overhead of reviewing outputs and sequencing merges starts to outweigh what the added parallelism is worth. Layout conventions don't remove that ceiling, and no amount of tooling sophistication raises it much further. What they do is make sure the agents working under it don't corrupt each other's output before a human even gets the chance to review it.
Sources
- Supercharging Development: Using Git Worktree & AI Agents | by Mike Welsh | Medium
- Git Worktrees for AI Coding: How to Run Multiple Agents Without Conflicts
- pnpm + Git Worktrees for Multi-Agent Development | pnpm
- Teach Your AI Agent How to Work in a Monorepo | Nx Blog
- Git Worktree Isolation Patterns for Parallel AI Agent Development | Zylos Research
- Git worktrees for parallel AI coding agents - Upsun Developer
- How to Use Git Worktrees to Run Multiple AI Agents on the Same Repo
- morphllm.com


