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:
- Agent A is refactoring the auth system
- Agent B is building a new search feature
- Both edit
package.json. Both touch shared types. Both run the dev server on the same port. - 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-authPaths 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, doneCompare 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 3142When 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
.envand 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 worktreeOr the PR-first flow:
git push -u origin claude/proj-141
# Merge via GitHub
wt remove claude/proj-141Why 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
- Install Worktrunk: worktrunk.dev
- Create your first worktree:
wt switch --create my-feature --base=^- Add hooks in
.config/wt.tomlto automate your setup (copy env files, symlink deps, etc.) - Launch an agent inside it:
wt switch --create my-feature --base=^ -x claude -- "Fix the auth bug"- 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 + cleanupFour aliases. That’s the entire workflow.
