Setting Up Worktrees for Agent Isolation
Directory organization patterns
Where worktrees live on the filesystem affects how easily they can be managed. Two patterns dominate: sibling directories and subdirectory containment.
Sibling directories place worktrees alongside the main repository:
~/projects/
├── myproject/ # main worktree
├── myproject-auth-refactor/ # linked worktree
├── myproject-api-endpoint/ # linked worktree
└── myproject-hotfix-login/ # linked worktreeThis pattern emerges naturally from git's default behavior.
Running git worktree add ../myproject-feature feature creates the worktree as a sibling.
Each worktree is visible at the same directory level, making tab completion and navigation straightforward.
The limitation: projects with active development accumulate many worktree directories in the parent folder.
Five parallel features plus a hotfix mean six worktrees cluttering ~/projects/.
Cleanup becomes manual inventory management.
Subdirectory containment keeps worktrees inside a dedicated folder:
~/projects/myproject/
├── .git/
├── .trees/ # worktree container
│ ├── auth-refactor/
│ ├── api-endpoint/
│ └── hotfix-login/
├── src/
└── ...Create this structure with:
mkdir .trees
git worktree add .trees/auth-refactor -b feature/auth-refactor mainAdd .trees/ to .gitignore to prevent accidental commits of the worktree container.
This pattern produces cleaner organization.
All worktrees for a project stay within that project's directory.
Deleting the project directory removes all contained worktrees.
The trade-off: deeper paths (cd .trees/auth-refactor) and potential confusion between the main working directory and the worktrees within it.
Which to choose depends on IDE behavior. Some editors struggle with worktrees nested inside the main project the containing project's configuration may interfere with the worktree's. VS Code handles nested worktrees well. JetBrains IDEs sometimes require opening worktrees as separate projects. Test your editor's behavior before committing to a pattern.
Naming conventions
Consistent naming prevents confusion when managing multiple worktrees.
Include the branch name or ticket number.
myproject-feature-auth tells you what's being worked on.
myproject-3 does not.
For ticket-based development, myproject-JIRA-1234 ties the worktree to the tracking system.
Prefix with the project name for sibling patterns.
When worktrees share a parent directory with other projects, myproject-feature distinguishes from otherproject-feature.
Use hyphens, not slashes.
Branch names with slashes are valid in git, but create problems when used in file paths.
The shell interprets feature/auth/refactor as nested directories.
Stick with hyphenated names like feature-auth-refactor for worktree directory names.
Number parallel attempts. When running multiple agents on similar tasks for comparison:
git worktree add .trees/auth-refactor-1 -b feature/auth-attempt-1 main
git worktree add .trees/auth-refactor-2 -b feature/auth-attempt-2 main
git worktree add .trees/auth-refactor-3 -b feature/auth-attempt-3 mainThree agents can implement the same feature independently. Compare results and merge the best implementation.
The one-branch-per-worktree constraint in practice
Git's enforcement that a branch can only exist in one worktree at a time has practical implications for ASD workflows.
Always create a new branch when adding a worktree.
The -b flag does this in one command:
git worktree add .trees/auth -b feature/auth mainThis creates the worktree and branch atomically.
Without -b, attempting to check out an existing branch that's already active elsewhere fails:
fatal: 'feature/auth' is already checked out at '/path/to/other/worktree'For throwaway or exploratory work, use detached HEAD.
git worktree add -d .trees/experiment HEADThe -d flag creates a worktree in detached HEAD state.
Commits made in detached HEAD belong to no branch.
This works well for agents exploring approaches without polluting the branch namespace.
When the experiment concludes, create a branch from worthwhile commits or discard everything.
Tracking remote branches requires explicit naming.
When a branch exists on the remote but not locally:
git worktree add --track -b feature/auth .trees/auth origin/feature/authThe --track flag sets up the upstream relationship; -b creates the local branch.
Environment setup per worktree
Git worktrees share the repository but not the development environment. Each worktree requires its own dependency installation, environment files, and build state.
Dependencies must be installed separately.
The node_modules/ directory, Python virtual environments, and Go module cache live in the working directory, not the shared .git/.
After creating a worktree:
cd .trees/auth-refactor
npm install # Node.js
# or
python -m venv venv && source venv/bin/activate && pip install -r requirements.txt # Python
# or
go mod download # GoUse pnpm for disk efficiency in JavaScript projects.
pnpm's content-addressable storage uses hard links to share package content across projects.
Five worktrees with npm consume 5× the node_modules size.
Five worktrees with pnpm share most of that storage, cutting disk usage substantially.
npm install -g pnpm
cd .trees/auth-refactor && pnpm installEnvironment files need copying.
Files in .gitignore don't transfer to new worktrees that includes .env, .env.local, and similar configuration files.
Manual approach:
cp .env .trees/auth-refactor/.env
cp .env.local .trees/auth-refactor/.env.localFor frequent worktree creation, automate with a setup script:
#!/bin/bash
# setup-worktree.sh
WORKTREE_PATH=$1
cp .env "$WORKTREE_PATH/.env"
cp .env.local "$WORKTREE_PATH/.env.local" 2>/dev/null || true
cd "$WORKTREE_PATH" && npm installPort conflicts require coordination. Multiple worktrees running development servers need different ports. A formulaic approach prevents collisions:
PORT = BASE_PORT + (WORKTREE_INDEX × 10)
Worktree 0 (main): 3000, 3001, 3002 (web, api, db)
Worktree 1: 3010, 3011, 3012
Worktree 2: 3020, 3021, 3022Configure ports via environment variables:
# .trees/auth-refactor/.env
WEB_PORT=3010
API_PORT=3011
DATABASE_PORT=3012Document which worktree uses which ports. When agents need to run tests or start servers, explicit port assignment prevents "address already in use" errors.
Task independence analysis
Not every task belongs in a parallel worktree. Before creating worktrees for parallel agent work, analyze whether the tasks can actually proceed independently.
Tasks are independent when they touch different files. Agent A refactoring authentication components and Agent B adding dashboard widgets rarely conflict. Different directories, different dependencies, minimal merge complexity.
Tasks are dependent when they modify shared interfaces. Agent A changing the user authentication API and Agent B building features that consume that API will produce incompatible code. Agent B's work assumes interfaces that Agent A is actively changing.
A quick heuristic: imagine merging the branches. If both agents modify the same files, merge conflicts are likely. If one agent's changes require the other agent to adjust, dependencies exist. If the changes can combine without discussion, independence is established.
When in doubt, sequence instead of parallelize. The overhead of conflict resolution often exceeds the time saved by parallel work. Two dependent tasks completing sequentially in 60 minutes beats two conflicting parallel tasks requiring 45 minutes of work plus 30 minutes of merge resolution.
Diagram task dependencies before creating worktrees. For larger efforts:
Feature: User management overhaul
Independent clusters:
├── Cluster A: Profile editing (3 tasks)
│ ├── Profile form component
│ ├── Avatar upload handler
│ └── Profile API endpoints
└── Cluster B: Team management (4 tasks)
├── Team list component
├── Team member invite flow
├── Team permissions UI
└── Team API endpoints
Dependencies between clusters:
└── User model changes → affects both clustersRun one worktree per independent cluster. Handle cross-cluster dependencies sequentially.
Practical mechanics
Putting it together: a complete worktree setup for parallel agent sessions.
1. Create the worktree structure:
mkdir -p .trees
git worktree add .trees/feature-auth -b feature/auth main
git worktree add .trees/feature-dashboard -b feature/dashboard main2. Set up environments:
for wt in .trees/*/; do
cp .env "$wt/.env"
cp .env.local "$wt/.env.local" 2>/dev/null || true
done3. Install dependencies:
for wt in .trees/*/; do
(cd "$wt" && pnpm install)
done4. Configure unique ports (create or update .env in each worktree):
echo "WEB_PORT=3010" >> .trees/feature-auth/.env
echo "WEB_PORT=3020" >> .trees/feature-dashboard/.env5. Launch agents in separate terminals:
# Terminal 1
cd .trees/feature-auth && claude
# Terminal 2
cd .trees/feature-dashboard && claudeEach agent operates in complete isolation. Both access the same git history. Both can commit, branch, and work without interfering with the other.
The next section covers running multiple agents in parallel: manual approaches, orchestration tools, and monitoring patterns for keeping track of what each agent accomplishes.