How to Run Parallel AI Coding Agents on One Python Project
Run each AI coding agent in its own git worktree, and give each worktree its own uv environment. A worktree is a second working directory on its own branch, backed by the same .git store. One uv sync per worktree produces an isolated virtual environment, so Claude Code, Codex, and Cursor can work in parallel, each on its own branch and in its own .venv, without sharing a working tree.
Confirm your starting point
You need an existing uv project with a pyproject.toml (the first uv sync creates the uv.lock and .venv if you don’t have them yet), uv installed, and git 2.17 or newer, which is where git worktree remove landed. Run these commands from the root of that project.
Create a worktree for each agent
Add one worktree per task, each on a fresh branch:
git worktree add ../myproject-auth -b agent-auth
git worktree add ../myproject-docs -b agent-docsEach command creates a sibling directory (../myproject-auth) checked out to a new branch (agent-auth). Creating a worktree is cheap: it links to the existing .git store instead of copying history.
List what you have:
git worktree list/path/to/myproject a1e219e [main]
/path/to/myproject-auth a1e219e [agent-auth]
/path/to/myproject-docs a1e219e [agent-docs]
Give each worktree its own environment
Each worktree is a separate checkout, so give each its own environment rather than sharing one. A .venv records absolute paths tied to the directory it was created in, and for a workspace, sharing one sends imports to the wrong source tree (Keep uv workspaces isolated across worktrees).
cd ../myproject-auth
uv syncCreating virtual environment at: .venv
Installed 7 packages in 3ms
The first uv sync populates uv’s global cache. Every later sync, including ../myproject-docs, hardlinks from that cache: a small project finishes in a few milliseconds, a large dependency set (torch, numpy) in seconds.
cd ../myproject-docs
uv syncAdd .venv/ to your .gitignore if it is not already there. Worktrees share one .git object store, so an agent that commits its .venv bloats that store for every worktree, and the bloat survives even after you delete the branch.
Tip
Wrap both steps in a shell function so spinning up a new agent is one command:
new-agent() { git worktree add "../$1" -b "$1" && (cd "../$1" && uv sync); }
# new-agent agent-authPoint each agent at its worktree
Open a separate terminal per worktree, cd into it, and start the agent there. For terminal agents like Claude Code and Codex:
cd ../myproject-auth && claude # or: codexFor Cursor, open the worktree as a folder (File > Open Folder, then select ../myproject-auth) so the editor and its agent operate on that branch.
An agent started in the worktree runs its shell commands against that branch and .venv. For a uv project, uv run and uv sync select the .venv at the worktree (project) root, so uv run pytest from ../myproject-auth tests the agent-auth branch in its own environment. To make Claude Code activate that .venv before running tools, see How to configure Claude Code to use virtual environments; the same principle applies to Codex and Cursor.
Warning
If UV_PROJECT_ENVIRONMENT is set in the agent’s environment, especially to an absolute path, uv uses that one environment for every worktree and collapses the isolation. Unset it so each worktree gets its own .venv.
Keep uv workspaces isolated across worktrees
A uv workspace keeps its .venv and uv.lock at the workspace root. In a worktree, that root is the worktree’s own directory, so uv sync there builds a self-contained environment whose members resolve from that worktree’s source. No extra configuration is needed.
Don’t share one .venv across worktrees to save disk. Workspace members install as editable, so the environment stores an absolute path to one worktree’s source. A second worktree pointed at that shared environment imports the first worktree’s code:
# Correct: each worktree's own uv sync
wt-auth resolves shared_lib -> /path/to/myproject-auth/packages/shared-lib/src
wt-docs resolves shared_lib -> /path/to/myproject-docs/packages/shared-lib/src
# Broken: myproject-docs pointed at myproject-auth's shared .venv
myproject-docs imports shared_lib -> /path/to/myproject-auth/packages/shared-lib/src
An edit in one agent’s worktree then silently changes what the other runs. A separate uv sync per worktree costs little from uv’s cache and keeps each pointed at the right source.
Review and merge each agent’s work
Each agent’s changes live on its own branch. Review one worktree’s commits, then merge the branch or open a pull request:
git -C ../myproject-auth log --oneline main..agent-auth
git switch main && git merge agent-authWhen several agents finish at once, open a pull request per branch (gh pr create from each worktree) so the reviews stay separate. Enough Git to Supervise Your AI Coding Agent covers branches and pull requests in more depth.
Clean up a worktree when the agent is done
After merging a branch, remove its worktree and delete the branch:
git worktree remove ../myproject-auth
git branch -d agent-authgit worktree remove deletes the directory, including its .venv. If an agent left uncommitted changes, git refuses to remove the worktree; inspect them first, then pass --force if you want to discard them.
Learn More
- How to set up a Python monorepo with uv workspaces covers the workspace layout these worktrees check out.
- git worktree documentation is the reference for
add,list,remove, andprune. - uv workspaces documentation describes how members share a lockfile and environment.