Edu Wass

Software Engineer.

Git Worktrees + Worktrunk: A Setup for Parallel AI Agents

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.

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:

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

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:

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

This creates the worktree, checks out a new branch from main, and cds 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:

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:

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:

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

Or the PR-first flow:

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

Why This Beats the Alternatives

ApproachShared historyDisk costSetup timeAgent isolationLifecycle hooks
Single branchYesZeroZeroNoneN/A
Separate clonesNoHighSlowFullNone
Raw git worktreeYesLowMediumFullNone
wt (Worktrunk)YesLowInstantFullYes

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
  2. Create your first worktree:
   wt switch --create my-feature --base=^
  1. Add hooks in .config/wt.toml to automate your setup (copy env files, symlink deps, etc.)
  2. Launch an agent inside it:
   wt switch --create my-feature --base=^ -x claude -- "Fix the auth bug"
  1. 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:

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

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

Four aliases. That’s the entire workflow.