Two coding agents in one checkout will overwrite each other, and no amount of prompting fixes it. Git worktrees give each agent its own directory on its own branch against one object store. The commands, the directory layout, the cleanup, and the five ways it still goes wrong.
why one checkout breaks
Two coding agents pointed at one working directory will overwrite each other, and there is no prompt that prevents it. The reason is mechanical rather than behavioural. An agent reads a file into its context, thinks for thirty seconds, and writes the file back. If a second agent wrote to that file during the thirty seconds, the write lands on top of it and the earlier edit is gone. Git never sees a conflict, because a conflict requires two commits. What happened here is one commit containing one of the two changes, which is a lost update.
The second failure is worse because it is invisible. A branch is a property of the working directory, not of a process. If one agent runs git checkout, git stash or git rebase, every other process in that directory is now looking at different files than the ones it read a minute ago, and none of them will be told. Each will notice its own edits appear to have vanished, conclude it made a mistake, and start confidently repairing damage it did not cause.
You can dodge both by giving each agent its own clone, and for a small repository that is a reasonable answer. It stops being reasonable when the repository is large, when you want commits from one agent visible to another without a remote round trip, or when you are creating and destroying these directories several times a day. That is the job a worktree does.
what a worktree actually is
A git worktree is a second working directory attached to a repository you already have. It sits wherever you put it, it is checked out on its own branch, and it shares one object database with the original checkout. Git has supported this since version 2.5, so unless you are on something ancient it is already installed.
The mechanics are worth knowing because they explain every quirk further down. In a normal checkout .git is a directory. In a worktree, .git is a single file containing one line:
$ cat ../wt-schema/.git
gitdir: /Users/you/code/myapp/.git/worktrees/wt-schemaThat points at a small per-worktree administrative directory inside the original repository, holding this worktree's HEAD, its index and its own reflog. Everything else lives in the one shared directory. A worktree is not a copy of the repository, it is a second head on the same body.
The last row is the one that matters for agents. When the agent working on your schema commits, the agent working on your API can merge that branch immediately, with no remote involved. Three clones would need a push, a fetch, and somewhere to push to.
creating one per agent
Start in your existing checkout, on the branch you want to branch from, and create one worktree per slice of work. The -b flag creates the branch at the same time.
cd ~/code/myapp
git worktree add ../wt-schema -b feat/schema
git worktree add ../wt-api -b feat/api
git worktree add ../wt-checkout -b feat/checkout
git worktree listgit worktree list is the command to keep in your head. It prints one line per worktree with the path, the current commit and the branch, and it is the only reliable answer to "what have I got open right now":
/Users/you/code/myapp afa9821 [main]
/Users/you/code/wt-api afa9821 [feat/api]
/Users/you/code/wt-checkout afa9821 [feat/checkout]
/Users/you/code/wt-schema afa9821 [feat/schema]Add --porcelain if you want to parse it from a script. That is the stable format, one field per line, and is what tooling should read rather than the columns above.
the argument forms worth knowing
git worktree add ../wt-api -b feat/apicreates a new branchfeat/apiat the current HEAD and checks it out there. This is the one you will use nearly always.git worktree add ../wt-api feat/apichecks out an existing branch. It fails if that branch is checked out anywhere else, which is a feature and is covered below.git worktree add ../wt-apiwith no branch argument creates a branch named after the directory, which is how people end up with branch lists full of directory names. Pass-b.git worktree add --track -b feat/api ../wt-api origin/feat/apicreates a local branch tracking a remote one, for picking up work that already exists.git worktree add --detach ../wt-look v1.4.0gives a detached HEAD at some commit, for letting an agent read an old version without a branch it might commit to.
Then launch each agent inside its own worktree, and leave your original checkout without an agent in it. That directory is where you read diffs, run the full suite and merge. One directory that is always clean is what tells you whether the repository is broken or merely mid-edit somewhere else.
cd ../wt-schema && claude # terminal 1
cd ../wt-api && codex # terminal 2
cd ../wt-checkout && gemini # terminal 3Name the branches after the work rather than after the agent. feat/schema, not claude-2. The branch outlives the session, and in a week the useful question about a commit is what it was trying to do, not which vendor's CLI typed it.
where to put them
There are two layouts and the choice matters less than picking one and staying with it. Siblings of the repository:
~/code/
myapp/ <- the original checkout, always on main
wt-schema/
wt-api/
wt-checkout/Or nested inside the repository, in one hidden directory:
~/code/myapp/
.worktrees/
schema/
api/
checkout/Nesting is tidier and has one requirement people discover by accident. The nested directories are untracked files inside the repository, so git status in the main checkout reports them and an agent told to "commit everything" will try to commit a whole second checkout. Add the directory to .gitignore first:
echo '.worktrees/' >> .gitignore
git add .gitignore && git commit -m "ignore worktree directory"The failure this prevents: a commit that adds three thousand files nobody meant to add, produced by an agent following an instruction that was correct everywhere else.
what does not come across
A worktree contains tracked files and nothing else. This catches everyone exactly once and it is the single most common reason a fresh worktree does not build. Your .env.local is gitignored, so it is not there. node_modules is gitignored, so it is not there either. Neither is your local editor config, your database file, or whatever else you have accumulated that git has been told to ignore.
cd ../wt-api
cp ../myapp/.env.local . # gitignored, so it did not come across
npm install # node_modules is per worktree
PORT=3001 npm run dev # and a port nobody else is usingAssign the ports at the same time you assign the directories. Two dev servers fighting over port 3000 is the most boring failure in this whole subject and it eats afternoons, because the symptom is a page that loads from the wrong branch rather than an error. If something is already listening, find out what before you go looking in the application:
lsof -i :3000If bootstrapping takes more than two commands in your stack, make it one script committed to the repository. An agent can run it too.
submodules
Submodules are the part where the honest answer is that this is not fully supported. A new worktree gets the submodule directories created and empty. You have to initialise them inside that worktree:
cd ../wt-api
git submodule update --init --recursiveThat works. But git's own manual page for worktree carries a BUGS section saying that support for submodules is incomplete and that multiple checkouts of a superproject are not recommended. Two visible consequences: git worktree move refuses to move a worktree containing submodules, and git worktree remove needs --force on one. Read that section in git help worktree before building a submodule-heavy repository into a fan-out workflow.
The failure this prevents: an agent spending a lot of tokens debugging a missing module that was never missing, only never installed in the directory it was standing in.
removing them again
Worktrees are meant to be disposable. The tidy-up is three commands in this order, and the order is the one the previous section explains:
git worktree remove ../wt-schema
git worktree prune
git branch -d feat/schemaremove deletes the directory and the administrative entry together. prune forgets entries whose directories no longer exist, which is what you run after deleting one by hand. Deleting the branch is separate, because git will not let you do it while the worktree is still there.
remove only removes clean worktrees. Any modified tracked file or any untracked file at all and it refuses:
$ git worktree remove ../wt-api
fatal: '../wt-api' contains modified or untracked files, use --force to delete itUntracked counts: a stray log file is enough. That refusal does real work in an agent setup, because what is in there is an agent's unfinished work and you cannot see it from outside. Look before you reach for --force:
git -C ../wt-api status --short
git -C ../wt-api diffIf you delete a directory outside git, git worktree list keeps showing it with a prunable annotation until you prune. Nothing is broken in the meantime and prune -v tells you exactly what it dropped and why. Two smaller commands round it out: git worktree lock marks a worktree that must not be pruned or removed, taking a --reason that gets printed back when you try, and git worktree repair reconnects the administrative files after you moved a directory by hand rather than with git worktree move.
five ways it still bites
Worktrees solve one problem completely: two processes writing the same files. They do not solve any of the others, and pretending otherwise is how a setup that looks clean produces a merge that is not.
1. Nothing enforces the boundary
A worktree is a directory, not a permission. An agent in wt-api can edit db/ if it decides to, and git will happily commit it to feat/api. There is no per-branch path restriction in git, CODEOWNERS does nothing locally, and a scope rule in a prompt is a suggestion. The enforcement is you reading the file list before you read any code:
git diff --name-only main...feat/apiThat is the cheapest check available. A branch that touched directories it was not assigned is something you want to know in one line rather than three hundred. The wider question of who is allowed to do what, and who is allowed to instruct whom, is covered in who may command whom.
2. Shared files still conflict
Lockfiles are the classic. Three agents each adding a dependency produce three different package-lock.json files and a merge nobody can resolve sensibly, because no human wrote any of them. Add dependencies yourself, on the base branch, before the fan-out. The same goes for generated code, applied migrations and CI configuration.
3. Divergence is silent
Each worktree is frozen at the commit it was created from. Nothing pulls. An agent working against a base that moved an hour ago is writing code against an API that no longer exists, and it will not find out until merge time. Rebase the long-running ones periodically, or keep the fan-out short enough that it does not matter.
4. The disk cost is not the git cost
The object database is shared, so worktrees are cheap in git terms. The working files are not, and neither is node_modules. Four worktrees of a JavaScript project is four dependency trees, usually far more disk than the repository itself. A reason not to leave a dozen lying around, not a reason to avoid them.
5. It does not make the work parallel
This is the important one. A worktree gives you isolation. It does not give you a decomposition. If the work does not genuinely split into pieces that touch different files, four worktrees produce four branches that all edit the same module and a merge that is worse than doing it once in sequence. Deciding the split is the human step and it comes first, which is the subject of running agents in parallel and, in longer form with a plan file, of setting up a multi-agent workspace.
common questions
Can two AI coding agents work in the same git repo?
Not in the same checkout. Two agents editing one working directory overwrite each other and change the branch under one another. They can share one repository if each gets its own git worktree, which is a separate directory on a separate branch backed by the same object store. Launch each agent inside its own directory, and keep your original checkout free of agents so you have somewhere clean to read diffs and merge.
What is a git worktree?
A git worktree is a second working directory attached to an existing repository, checked out on its own branch, sharing one .git object database. Create one with git worktree add ../dir -b branch. It is cheaper than a clone and everything committed in it is immediately visible to the original checkout, with no remote and no fetch. Git has supported worktrees since version 2.5.
Why does git worktree remove refuse to run?
git worktree remove only removes clean worktrees. If the directory has modified tracked files or any untracked file, it refuses with contains modified or untracked files, use --force to delete it. That refusal is protecting uncommitted agent work, so run git -C <path> status --short and read the diff before you force it. A worktree containing submodules also needs --force, even when clean.
Do git worktrees copy node_modules and .env files?
No. A worktree contains tracked files only, so anything gitignored is absent. Every new worktree needs its own dependency install and its own copy of gitignored environment files before an agent can build in it. Give each one a distinct dev server port at the same time, because two servers on one port presents as a page served from the wrong branch rather than as an error.
Do git worktrees work with submodules?
Partly. Submodule directories in a new worktree are created empty and need git submodule update --init inside that worktree. Git's own manual states that submodule support is incomplete and advises against multiple checkouts of a superproject. In practice git worktree move will not move a worktree containing submodules, and remove needs --force. Read the BUGS section of git help worktree first.
How many worktrees should I create for coding agents?
As many as you can review. Worktrees cost almost nothing to create, so the limit is not disk or git, it is how many diffs one person can read carefully in a sitting. For most people that is two or three. The number of cores on your machine is irrelevant to this, because it does not read the diff.
one implementation
We build a macOS app called Skribbl that folds this bookkeeping into the workspace: real terminals on a canvas, where spawning a group of agents creates the worktree first, because the worktree path is the working directory each agent launches into and cannot be created afterwards. It is the same git underneath, and every command above works with no app installed. The docs describe how it works, the comparison page puts it next to the other tools in this space, and the download page has the build.
If you are running one agent at a time and it is working, none of this is urgent. Worktrees are worth learning the day you first want two.