The Best Tool for AI Agents Is Eleven Years Old
There is a feature that has been sitting in git since 2015, shipped in version 2.5, roughly eleven years old at this point, and almost nobody uses it. I mean that literally: I have worked with a lot of engineers, and I can count on one hand the number who reach for git worktree without prompting. It has quietly waited in the tool for over a decade for a workload that would make it obvious. That workload finally arrived, and it is not a human one. It is coding agents.
I want to make a specific claim and then defend it honestly, including the parts where it falls apart. The claim is this: the single most useful tool for working with AI coding agents is not an AI tool at all. It is a version control primitive older than most of the frameworks the agents are writing code in.
What a worktree actually is
Start with the mechanics, because the value follows directly from them. A normal git clone has one working directory. You are on a branch, the files on disk reflect that branch, and switching branches mutates those files in place. If you have uncommitted work, git either carries it along or stops you. This is the model everyone internalizes: one repository, one checkout, one branch visible at a time.
A worktree breaks the assumption that a repository has exactly one working directory. With git worktree you can have multiple working directories attached to the same repository, each checked out to a different branch, all at the same time, on disk, simultaneously. They share one object database. They share the same refs, the same history, the same packed objects sitting in .git. What they do not share is working state: the files in the tree, the index, the currently checked out branch, the in-progress edits.
The surface area is small. Three commands do the real work:
git worktree add ../feature-x feature-xcreates a new directory withfeature-xchecked out.git worktree listshows every worktree attached to the repo and what each has checked out.git worktree remove ../feature-xtears one down when you are done.
That is essentially the whole interface. Under the hood git stores the linked worktree's administrative files under .git/worktrees/<name>, and the linked directory gets a .git file (not a folder) pointing back to it. One object store, many windows onto it. A branch can only be checked out in one worktree at a time, which is git protecting you from two trees fighting over the same ref, and that constraint turns out to be a feature rather than a limitation.
Why this fits agentic work so precisely
Now the interesting part. Why does an eleven year old feature suddenly feel purpose-built for a workload that did not exist when it shipped?
Because the defining problem of working alongside a coding agent is contention over working state. When I run Claude Code, it edits files. If it edits files in the same directory I am editing files in, we are two writers on one mutable surface. The agent renames a function while I am halfway through a change that references it. It runs a formatter across the tree while I am reading a diff. It leaves the repo in some intermediate state and I cannot tell what is mine and what is its. This is not a hypothetical. This is the default experience of letting an agent loose in your checkout, and it produces a specific feeling that I would describe as low-grade anxiety: you are never quite sure the ground under you is stable.
A worktree removes the contention by giving the agent its own working directory. The agent gets ../atlas-agent on its own branch. I keep the main checkout on mine. It is not touching my files because it physically cannot see them as its working tree; it has its own. I am not touching its files. We share history, so the moment it commits, I can fetch and inspect exactly what it did, but until that moment our working states are isolated. The isolation is the point.
Four properties make this land for agents specifically:
- Isolation of working state. The agent's half-finished edits, its failed experiment, its formatter run, none of it touches my tree. The blast radius of a bad agent run is one directory I can delete.
- Parallelism. I can run two or three agents at once, each in its own worktree on its own branch, genuinely in parallel. There is no shared index to serialize them. On agentic workflows this matters more than it does for humans, because agents are cheap to run concurrently and a human is not.
- A clean review and merge boundary. When the agent finishes, its work is a branch. I review the diff between its branch and mine the same way I would review a colleague's pull request, merge what I want, discard what I do not. The boundary between "the agent's work" and "my work" is a git ref, which is exactly the granularity code review already understands.
- No stash-and-switch context loss. I never have to abandon my own in-progress state to go look at what the agent did. Both states coexist. This is the difference between a workflow and an interruption.
That last one is where I lived before I understood worktrees, and it is worth naming the old workflow precisely, because most people are still in it.
The workflow I was actually running before
Here is the honest before-picture. I would be mid-change on something. The agent needs to run. So I stash. Then I switch to the branch the agent should work on, or worse, I just let the agent run in my working directory and hope it does not step on the change I was in the middle of. Then the agent finishes, I switch back, I git stash pop, and half the time I have forgotten what was in the stash or the pop conflicts with something the agent left behind. Multiply that by every context switch in a day.
That is not a workflow. That is a sequence of small anxieties strung together with git stash. The stash is a symptom. Reaching for stash constantly is git telling you that you are trying to be in two working states at once with a tool that only allows one. Worktrees are the tool that allows the two states. Once I moved to them the stash basically disappeared from my daily vocabulary, and that absence is the tell that something structural improved.
The generalizable principle
Pull this up a level, because the specific trick matters less than the shape of it. The pattern is: when you introduce a new concurrent actor into a system, the scarce resource becomes isolation, and you should reach for the primitive that provides isolation cheaply rather than inventing a new mechanism.
Agents are concurrent actors. The instinct across the industry right now is to build elaborate new machinery to manage them: sandboxes, orchestration layers, custom file-locking, bespoke "agent workspaces." Some of that is genuinely necessary. But a lot of the coordination problem was already solved decades ago by version control, because version control has always been about many actors mutating shared state without clobbering each other. That is the entire job description of git. The agent is just another contributor. Treat it like one. Give it a branch, give it an isolated working directory, review its diff, merge deliberately.
The broader lesson I keep relearning while building Atlas is that the arrival of agents does not obsolete the old tools. It re-illuminates them. Features that looked niche, that looked like they were for some exotic release-engineering edge case, turn out to be exactly the right shape once you have a second entity editing your code. Worktrees are the clearest example I have found, but they will not be the last. The most leveraged move is often not adopting a new AI-native tool; it is noticing which boring, battle-tested primitive was quietly waiting for this exact reason to exist.
Where this breaks, honestly
If I stopped here it would be a LinkedIn post, and the whole point of writing these longer is to steelman the skeptic. So here is where worktrees are genuinely awkward, and where I would tell you to use something else.
Disk cost and duplicated environment state. Worktrees share the git object database, so the history is not duplicated, which is the part people worry about and the part that is actually fine. What is not shared is everything git does not track, and that is where the real cost lives. Each worktree is a full working directory, so each one gets its own node_modules, its own Python venv, its own target/ or build cache, its own compiled artifacts. On a project with a heavy dependency tree, three worktrees can mean three multi-gigabyte node_modules installs and three cold build caches. The git-tracked part is cheap. The untracked environment around it is not, and it can dominate. There are mitigations (pnpm's content-addressed store, shared caches via environment variables, Docker layers) but they are extra setup, and the naive experience is real duplication.
Cold environments per tree. Related but distinct: a fresh worktree is not just disk, it is time. You npm install again, you rebuild, you re-warm whatever caches your test suite depends on. For a quick one-off task, the setup cost of a new worktree can exceed the cost of the task. That is a real tax, and for small quick work a plain branch switch in place is often just faster.
Tooling that assumes one checkout. A lot of tooling quietly hardcodes the assumption that a repo is one directory. Some IDEs get confused pointing at a linked worktree, or index poorly across several. File watchers, language servers, and dev containers sometimes assume a single root. Scripts that compute paths relative to .git being a directory can trip on the fact that a linked worktree's .git is a file. None of this is fatal, but you will hit rough edges that a single checkout never surfaces.
Submodules and shared state. Submodules are a known sore spot; they are per-worktree working state layered on top of the object sharing, and getting them consistent across worktrees is fiddly. Anything that lives outside the object database and outside the tracked tree (local config, untracked secrets, .env files you did not commit, editor state) does not come along for free, and you will notice each one the first time an agent's worktree does not have it.
When a branch or a throwaway clone is simply simpler. If you are not running concurrently, if the agent runs, finishes, and hands back before you touch anything, you may not need isolated working directories at all; a branch you switch to and from is enough. And at the other extreme, if you want total isolation including a separate object store (say you are letting an untrusted process run, or you want to blow the whole thing away without any chance of touching your real repo), a plain git clone into a throwaway directory is more isolated and easier to reason about than a worktree that still shares your object database. Worktrees occupy the useful middle: cheaper than a clone, more isolated than a branch. But the middle is not always where you want to be, and pretending it is would be dishonest.
My rule of thumb: reach for a worktree when you have real concurrency (you and an agent, or several agents, editing at once) and you want a clean per-branch review boundary. Reach for a plain branch when the work is sequential and cheap. Reach for a throwaway clone when you want maximal isolation and do not care about the disk. The mistake is using one of the three for all three situations.
The part that keeps surprising me
The thing I cannot get over is the timing. This feature shipped in 2015. It has been in every git install on every machine I have owned for over a decade. I typed git tens of thousands of times without it ever occurring to me that I might want two checkouts at once, because as a solo human I basically never did. The demand simply was not there. And then a new kind of collaborator showed up, one that edits files concurrently and cheaply and in parallel, and a dormant feature snapped into focus as if it had been designed for this all along.
It was not designed for this. It was designed for release engineers maintaining several long-lived branches. But good primitives generalize past their original motivation, and that generalization is where a lot of leverage hides. The best tool I have found for working with AI coding agents is not an AI tool. It is a version control feature older than most of the frameworks the agents are writing in, and it was sitting in plain sight the entire time.
So the question I will leave you with is the one I keep asking myself as I build Atlas: what other boring, battle-tested feature is quietly waiting for a reason to exist, and will you notice it before or after everyone starts writing a worse version of it from scratch?