---
title: "Git Worktrees + Worktrunk: A Setup for Parallel AI Agents"
date: 2026-02-16
slug: git-worktrees-worktrunk-a-setup-for-parallel-ai-agents
description: "If you're using AI coding agents — Claude Code, Codex, Cursor — and you're still working on a single branch, you're leaving a massive productivity multiplier…"
---

If you're using AI coding agents — Claude Code, Codex, Cursor — and you're still working on a single branch, you're leaving a massive productivity multiplier on the table.

I've been running parallel AI agents on a monorepo and the single biggest workflow unlock wasn't a better prompt or a faster model. It was **git worktrees**, managed by [Worktrunk](https://worktrunk.dev).

## The Problem: Agents Need Isolation

Here's what happens when you run multiple AI agents on the same repo:

1. Agent A is refactoring the auth system
2. Agent B is building a new search feature
3. Both edit `package.json`. Both touch shared types. Both run the dev server on the same port.
4. Everything breaks.

Separate clones? Duplicated `node_modules`, `.env` files, git history. On a monorepo with heavy dependencies, each clone costs gigabytes.

## Git Worktrees: The Primitive

Git worktrees let you check out multiple branches from the **same repository** simultaneously, each in its own directory. They share the `.git` object store — no duplication.

The problem is the native UX is terrible:

```bash
git worktree add -b feat/auth ../my-project.feat-auth && cd ../my-project.feat-auth
```

Paths are manual. Cleanup is manual. There's no lifecycle hooks, no coordination, no agent awareness.

## Enter Worktrunk

[Worktrunk](https://worktrunk.dev) (`wt`) wraps git worktrees with a proper developer experience. Branch names become the primary identifier, paths are computed from templates, and lifecycle hooks let you automate the boring parts.

Three commands cover 90% of the workflow:

```bash
wt switch -c claude/proj-141    # Create worktree + branch, cd into it
wt list                          # See all worktrees with status
wt merge main                    # Squash-merge, cleanup, done
```

Compare that to the raw git equivalent and it's night and day.

## My Actual Workflow

### One Worktree Per Task

Each ticket gets its own worktree. I use a naming convention that encodes the agent and issue:

```bash
wt switch --create claude/proj-141-auth-refactor --base=^
```

This creates the worktree, checks out a new branch from `main`, and `cd`s me into it. Worktrunk's hooks handle the rest: copying `.env` files, symlinking `node_modules`, setting up dependencies.

### Launch an Agent Directly

Worktrunk's `-x` flag lets you launch an agent in one shot:

```bash
wt switch --create claude/proj-141 --base=^ -x claude -- \
  "Read the ticket for PROJ-141. Propose a plan first."
```

That creates the worktree, switches into it, and spawns Claude Code with the initial prompt. One command, fully isolated agent session.

### Deterministic Ports, Zero Coordination

Each issue maps to a port: `PROJ-N → port 3000 + N`. No coordination needed between agents:

```bash
PROJ-128 → port 3128
PROJ-142 → port 3142
```

When I run the dev server inside a worktree, it auto-detects the branch name, derives the port, and starts in lite mode (just the web server — no duplicate workers or schedulers).

### Lifecycle Hooks Do the Housekeeping

This is where Worktrunk really shines. In `.config/wt.toml`, I define hooks for every phase:

**post-create** — Fresh worktree is immediately runnable:

- Copies `.env` and other ignored files
- Symlinks `node_modules` (no reinstall needed)
- Symlinks heavy data directories

**pre-merge** — Automated verification gate:

- Lint → typecheck → tests
- Failures abort the merge

**post-remove** — Kills orphaned dev servers, cleans up routing config.

No manual cleanup. No forgotten processes hogging ports.

### Merge and Clean Up

When an agent finishes:

```bash
wt merge main           # pre-merge hooks verify, squash-merge, auto-remove worktree
```

Or the PR-first flow:

```bash
git push -u origin claude/proj-141
# Merge via GitHub
wt remove claude/proj-141
```

## Why This Beats the Alternatives

| Approach | Shared history | Disk cost | Setup time | Agent isolation | Lifecycle hooks |
| --- | --- | --- | --- | --- | --- |
| Single branch | Yes | Zero | Zero | None | N/A |
| Separate clones | No | High | Slow | Full | None |
| Raw `git worktree` | Yes | Low | Medium | Full | None |
| **`wt` (Worktrunk)** | **Yes** | **Low** | **Instant** | **Full** | **Yes** |

## The Multiplier Effect

The real power isn't "two agents instead of one." It's that worktrees + Worktrunk remove the **coordination overhead** between parallel workstreams. Without them, you're stashing, rebasing, and resolving conflicts just to let two agents coexist. With them, each agent operates in a clean environment, and you deal with integration at merge time — which is exactly when you *want* to think about how pieces fit together.

On a typical day I'll have 2–3 worktrees active: one for a feature, one for a bug fix, and the main tree as a control room for review. Each with its own agent session, its own dev server. The throughput increase isn't linear (merge conflicts and review are still sequential), but it's meaningfully higher than working serially.

## Getting Started

1. Install Worktrunk: [worktrunk.dev](https://worktrunk.dev)
2. Create your first worktree:

```bash
   wt switch --create my-feature --base=^
```

3. Add hooks in `.config/wt.toml` to automate your setup (copy env files, symlink deps, etc.)
4. Launch an agent inside it:

```bash
   wt switch --create my-feature --base=^ -x claude -- "Fix the auth bug"
```

5. When done: `wt merge main`

No plugins, no complex infra. Just a CLI that makes git worktrees actually usable — and turns them into the perfect isolation layer for the age of agentic coding.

## Bonus: Shell Aliases

Once worktrees become second nature, even `wt switch --create` feels verbose. I keep these in my `~/.zshrc`:

```bash
# worktrunk aliases
# see: https://worktrunk.dev/tips-patterns/
alias wtc='wt switch --create'   # wtc feat/whatever (create new worktree)
alias wts='wt switch'            # wts feat/whatever (switch to existing)
alias wtr='wt remove'            # wtr feat/whatever (clean up)
alias wtm='wt merge'             # wtm main (verify + squash-merge + remove)
```

Now the full lifecycle fits in muscle memory:

```bash
wtc claude/proj-141               # create
# ... agent does its thing ...
wtm main                          # merge + cleanup
```

Four aliases. That's the entire workflow.
