Back to blog
Architecture

Git worktree isolation: how Phasr prevents agents from colliding

Mar 5, 20267 min read

When you run multiple AI agents against the same codebase, isolation isn't optional - it's the first thing you have to solve. Without it, agents overwrite each other's files, produce unresolvable merge conflicts, and generate diffs that make no sense because they were built on top of another agent's half-finished work.

The obvious solution is containers. Spin up a Docker container per agent, each with its own full copy of the repo. It's conceptually clean, but operationally heavy. Containers take seconds to start, consume significant memory, and require a container runtime on every developer's machine. For something that should feel like 'run five scripts at once,' that's a lot of infrastructure.

Git branches alone don't solve the problem either. Branches are just pointers - they don't give you separate working directories. If two agents are on different branches but share the same worktree, they'll clobber each other's uncommitted changes the moment one of them runs a checkout.

Git worktrees are the sweet spot. A worktree is a separate working directory linked to the same Git repository. It has its own checked-out branch, its own index, and its own working files - but it shares the object store with the main repo. Creating one is nearly instant. It uses minimal additional disk space because objects are shared. And it requires zero extra infrastructure beyond Git itself.

In Phasr, when you launch an agent task, the system creates a new worktree from the current HEAD. The agent operates in that worktree exclusively. It can read, write, run builds, execute tests - all without affecting the main working directory or any other agent's worktree. When the task is done, the changes are committed to the worktree's branch and presented for review.

The cleanup story is simple too. Worktrees are disposable. Once changes are merged (or discarded), the worktree is removed with a single command. There's no container image to garbage-collect, no VM to deprovision. It's just a directory that gets deleted.

There's one constraint: each worktree must be on a unique branch. You can't have two worktrees checked out to the same branch. Phasr handles this automatically by generating unique branch names per task (e.g., phasr/task-1742-add-rate-limiting). This also makes the Git log self-documenting - you can see exactly which branches were created by agents and trace them back to specific tasks.

We considered several alternatives during development - tmpfs copies, shallow clones, even overlay filesystems. Worktrees won because they require no special permissions, work on every OS, integrate with every Git GUI, and have zero ongoing maintenance cost. Sometimes the best architecture is the one that was already there.