AI + Git Worktree: a multi-agent setup that actually works
Sunday, March 22, 2026 · 7 min read
Something shifted. And it's not going back.
AI coding agents are reshaping how we build software and git worktree turned out to be the missing piece for running them in parallel.
But let me start from the beginning.
In the last 12 months alone many developers have seen their entire workflow flip upside down and with better LLMs coming out every few months, the bar to build something has dropped to basically zero. Your grandmother, your neighbor, probably someone's golden retriever with the right prompt...anyone can build an app now.
Vibe coding is real and it works. Or maybe not.
Because shipping real production software is a completely different sport: security, scalability, lifecycle, technical debt and architectural decisions that come back to bite you years later. Stuff no prompt fixes, at least not yet.
I've been doing this for over 15 years and I'll be honest I was starting to feel a bit bored. The work was solid but nothing felt truly exciting anymore, then AI showed up and something clicked. I didn't jump in overnight: first small tasks, then bigger ones, then I just stopped fighting it entirely. Claude Opus 4.5 and 4.6 were the real turning point for me personally, things I used to grind through in days started happening in hours and onboarding on a new codebase went from painful to almost fun. Almost.
The method. Structure first.
I work at Lago, an open source platform for metering and usage-based billing. React frontend, Rails API, event-driven architecture...not a codebase you want to throw a half-baked prompt at, so over time I've organized my work around 3 steps that keep things on track and that work, at least for me:
Step 1: Technical Solution. Before touching any AI tool I write up what needs to be built. Not a novel, just enough to make the architecture and the key decisions clear. This is the part that actually requires thinking. Get it wrong here and everything downstream suffers.
Step 2: Vertical ticket breakdown. The technical solution gets split into tickets. And here's the thing: these aren't tickets to make a PM feel good. They're dense technical documents with architectural reasoning, edge cases and enough context that an agent can pick one up and actually run with it. The size depends on complexity: sometimes it's 1 ticket, sometimes it's 8.
Step 3: Claude Code as executor. Each ticket goes to Claude Code along with the technical solution as background context. One agent, one ticket, one well-defined scope. The narrower the scope, the better the agent performs.
Pretty straightforward so far. Lots of people are doing some version of this.
The bottleneck. one ticket at a time.
Here's where it starts to break down.
Once I have all the tickets lined up I can see the entire feature in front of me and since each ticket is self-contained there's no reason they need to run sequentially. The problem is that git only lets you work on one branch at a time in a single directory, so in practice you're stuck doing one ticket after the other.
The workarounds are all not very effective to me:
- Clone the repo multiple times: works until it doesn't, wastes disk space and quickly turns into a mess
- git stash + manual checkout: fragile, error-prone and you're still switching context instead of running things in parallel
- Third-party tools: extra dependencies that add complexity without solving the core issue
And it gets worse in a real product setup. If your feature touches multiple repos, or depends on a branch that's still being worked on in another service, coordinating all of that by hand is genuinely awful.
The solution. git worktree.
This is where git worktree comes in. Shipped in July 2015 and honestly I'd never really explored it. Never had the right reason to and that's on me. But the multi-agent use case makes it actually essential.
The idea is simple: instead of cloning a repo multiple times you can have multiple working directories all pointing at the same .git object. Each directory lives on its own branch. No duplication, all worktrees share the same remote and the whole thing is one command.
Basic flow
cd ~/projects/my-app
# Create a worktree for the parallel ticket starting from the epic branch
git worktree add -b feature/dashboard-filters ../my-app-filters feature/dashboard
cd ../my-app-filters
# Work on the ticket
git add .
git commit -m "feat: add date range filter to dashboard"
git push -u origin feature/dashboard-filters
# Go back to main work
cd ../my-app
# Once the ticket is merged
git worktree remove ../my-app-filtersYou can branch off feature/dashboard, main or anything else. When tickets share the same base the final merge tends to be clean. Conflicts can still happen if two tickets touch the same files but at least you see them coming.
Why this matters for multi-agent setups
Each agent gets its own worktree. No stepping on each other, no shared state, no one agent undoing what another just did. Beyond that:
- Real parallelism: multiple terminals, multiple agents, each focused on one thing
- Independent testing: spin up each feature in isolation before merging anything
- Cleaner PRs: each one scoped tightly which makes reviews actually readable
Beyond the basics. Orchestrating a real architecture.
The simple case above works great for flat projects or monorepos with no external dependencies. Real architectures are messier.
At Lago we have a React frontend, a Rails API, a database, Redis and more all in play. Each worktree isn't just a branch. It's an environment. It needs its own ports, it needs to know which services to talk to and it needs to coexist with every other environment running at the same time without conflicts.
lago-worktree. A bash script to orchestrate it all.
My main work is on the frontend so I built a bash script to handle the orchestration starting from that layer. The idea is simple: each ticket gets its own worktree, its own port, its own isolated environment. If a ticket only touches the UI, the script creates a fresh frontend worktree on a free port and points it to the API already running from the main stack. If the ticket touches both frontend and API, it spins up dedicated worktrees for each. One command either way. Once every worktree is up, I can assign an agent to each one and let them all work in parallel, each focused on its own ticket without stepping on the others.
Frontend-only ticket:
lago-worktree create feat-01
# Front available at http://localhost:3001
# API shared with the main stack on :3000Ticket touching both frontend and API:
lago-worktree create feat-02 --from-front=feat/ui --from-api=feat/endpoint
# Front available at http://localhost:3002
# Dedicated API at http://localhost:4001See what's running:
lago-worktree ps
# NAME FRONT API STATUS
# feat-01 http://localhost:3001 [main] shared running
# feat-02 http://localhost:3002 [feat/ui] http://localhost:4001 [feat/...] runningClean up when done:
lago-worktree destroy feat-02
# Removes the branch and directory of the front worktree
# Removes the branch and directory of the API worktreeThe frontend and API get their own isolated instance per ticket. Database, Redis and the event streaming layer stay shared across all worktrees since every agent works against the same data and there's no need to duplicate them. This keeps resource usage low and setup fast. If the need arises to isolate other layers per worktree, the script is designed to be extended: just add a new flag for that layer and the orchestration handles the rest.
Parallelism works. I don't.
So now I have multiple independent instances of the full architecture running in parallel, each with a dedicated agent grinding through its ticket.
What's next? Well, the bottleneck now is me.
Agents produce code at a pace I can't keep up with when it comes to reviewing it and making sure it actually matches the solution. The more efficient the system gets the more obvious this gap becomes.
There's also a bigger shift worth naming: I almost stopped writing code and started directing it, context, architecture, vision, while the agents handle the execution. That's a good thing but it comes with a catch, the quality of what comes out is directly tied to the quality of my thinking. A vague ticket produces vague code, a wrong assumption gets implemented perfectly. Garbage in, garbage out and with agents it happens faster than ever.
How do I solve it? I don't know yet. But I'm working on it. Stay tuned.