# How to Run Parallel AI Coding Agents on One Python Project


Run each AI coding agent in its own [git worktree](https://git-scm.com/docs/git-worktree), and give each worktree its own [uv](https://pydevtools.com/handbook/reference/uv.md) 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](https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment.md), so [Claude Code](https://pydevtools.com/handbook/reference/claude-code.md), [Codex](https://pydevtools.com/handbook/explanation/codex-complete-guide.md), 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](https://pydevtools.com/handbook/reference/uv.md) project with a `pyproject.toml` (the first `uv sync` creates the `uv.lock` and `.venv` if you don't have them yet), [uv installed](https://pydevtools.com/handbook/how-to/how-to-install-uv.md), 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:

```bash
git worktree add ../myproject-auth -b agent-auth
git worktree add ../myproject-docs -b agent-docs
```

Each 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:

```bash
git worktree list
```

```console
/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](#keep-uv-workspaces-isolated-across-worktrees)).

```bash
cd ../myproject-auth
uv sync
```

```console
Creating 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.

```bash
cd ../myproject-docs
uv sync
```

Add `.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:
> ```bash
> new-agent() { git worktree add "../$1" -b "$1" && (cd "../$1" && uv sync); }
> # new-agent agent-auth
> ```

## Point 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:

```bash
cd ../myproject-auth && claude   # or: codex
```

For 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](https://pydevtools.com/handbook/how-to/how-to-configure-claude-code-to-use-virtual-environments.md); 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](https://pydevtools.com/handbook/how-to/how-to-set-up-a-python-monorepo-with-uv-workspaces.md) 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](https://pydevtools.com/handbook/explanation/what-is-an-editable-install.md), 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:

```console
# 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:

```bash
git -C ../myproject-auth log --oneline main..agent-auth
git switch main && git merge agent-auth
```

When 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](https://pydevtools.com/handbook/explanation/enough-git-to-supervise-your-ai-coding-agent.md) 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:

```bash
git worktree remove ../myproject-auth
git branch -d agent-auth
```

`git 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](https://pydevtools.com/handbook/how-to/how-to-set-up-a-python-monorepo-with-uv-workspaces.md) covers the workspace layout these worktrees check out.
- [git worktree documentation](https://git-scm.com/docs/git-worktree) is the reference for `add`, `list`, `remove`, and `prune`.
- [uv workspaces documentation](https://docs.astral.sh/uv/concepts/projects/workspaces/) describes how members share a lockfile and environment.
