← All Writing
June 26, 20267 min read

How I Run Multiple Claude Code Sessions in Parallel

Running several Claude Code agents at the same time without them stepping on each other — using git worktrees and a small shell tool called cmux, one agent per branch, on both my Mac and my always-on home Linux server, all on a single Max subscription

YieldSeveral Claude Code sessions running at once in the same repo — each on its own branch, in its own working copy, with zero file conflicts — plus one-word commands to create, resume, merge, and tear them down
DifficultyBeginner-to-intermediate (git worktrees, a shell function, terminal tabs — no code to write, mostly setup and workflow)
Total Cook Time~1 hour to install and wire up on both machines, plus a week of using it to figure out when it actually helps and when it just gets in the way

Ingredients

The Problem: One Agent at a Time Is Slow

Claude Code runs in a terminal. You open it in a folder, you talk to it, it edits files. That’s the whole thing, and it’s great — until you notice that most of the time you’re the bottleneck, not the AI. The agent goes off to write a feature, and you sit there watching it work. You can’t start the next thing, because if you open a second Claude Code session in the same folder, both agents edit the same files and you get a tangle: one overwrites the other’s work, tests fail for reasons that have nothing to do with the code, and you can’t tell which session broke what.

I kept hitting this. I’d have a small bug fix, a new blog post, and a refactor all queued up — three independent jobs, no reason they couldn’t happen at the same time — and I’d do them one after another because running them together was a mess.

The fix turned out to be a git feature I’d never used, plus a tiny tool that makes it painless.

The Idea: One Working Copy Per Agent

one git repomain branchcmux newworktree · fix-footerClaude agentworktree · new-postClaude agentworktree · refactor-searchClaude agentcmux mergeback into main
cmux gives each Claude agent its own git worktree — a separate working copy on its own branch — so several run at once without touching each other’s files. When one finishes, cmux merge folds its branch back into the main repo.

The reason two agents collide is that they share one set of files. So don’t share the files. Give each agent its own copy.

That’s exactly what a git worktree is — a second working copy of the same repo, checked out on its own branch, in its own folder, but still connected to the same underlying project history. You can have five of them. Each one is isolated: edits in one don’t touch the others. When a branch is done, you merge it back into the main copy like any normal branch.

So the mental model becomes: one worktree per agent, one branch per task. Agent A works in.worktrees/fix-footer on a branch called fix-footer. Agent B works in.worktrees/new-post on new-post. They never see each other’s files. When each finishes, I merge its branch and delete the worktree.

Worktrees are not copies you have to sync

The thing that made this click for me: a worktree isn’t a duplicate folder you have to keep in sync by hand. It’s the same repo, viewed on a different branch, in a different place on disk. Git handles the plumbing. You just get an isolated sandbox per task, for free, already built into a tool I use every day.

The Tool: cmux (tmux for Claude Code)

Worktrees are powerful but fiddly. The raw git commands are long, you have to invent a folder layout, remember which branch lives where, and manually launch Claude in each one. I didn’t want to type git worktree add ../whatever -b whatever ten times a day.

So I set up cmux — a small open-source shell tool (its tagline is “tmux for Claude Code”) that wraps the whole worktree lifecycle in one-word commands. It’s not a program you install into a folder — it’s a shell function you load in your terminal config. On my Mac that’s a line in ~/.zshrc; on the Linux server it’s a line in ~/.bashrc. Because it’s just a function, which cmux shows nothing — you check it withtype cmux instead. That surprised me the first time.

cmux was introduced on r/ClaudeCode, and that thread is a good window into how other people are wiring it into their Claude Code workflow — worth a skim to see the range of setups before you commit to one.

The important part for cost: cmux makes zero AI calls of its own. Every session it launches is a normal Claude Code session running on my Max subscription. There’s no separate API key, no per-token billing stacked on top — running four agents at once costs the same subscription as running one.

🔧 Developer section: the commands I actually use

A typical morning looks like: cmux new fix-footer in one terminal tab,cmux new new-post in a second, cmux new refactor-search in a third. Three Claude Code agents, three isolated working copies, all going at once. I glance between tabs, answer whichever one has a question, and let the others run.

What the Name Gets Wrong (and Why It Still Works)

The name “tmux for Claude Code” had me expecting it to split my screen for me. It doesn’t. Under the hood, cmux new just creates the worktree and then runsclaude in the terminal you’re already in — one session, front and center. The “parallel” part is on me: I open the sessions in separate terminal tabs (or iTerm2 splits on the Mac). cmux manages the worktrees; my terminal manages the windows.

Once I understood that split, it stopped being confusing. cmux’s job is to make sure each agent has a clean, isolated place to work and a one-word way to get in and out. Arranging the panes is a terminal problem, and my terminal already solves it.

The Setup Hook: Making a Fresh Worktree Actually Runnable

Here’s the catch nobody warns you about. A brand-new worktree is a clean checkout — which means it’s missing all the stuff that isn’t committed to git. My .env.localfile with API keys? Gitignored, so it’s not there. My node_modules folder with all the installed packages? Not there either. So the agent starts up, tries to run the site, and immediately fails because it has no secrets and no dependencies.

cmux solves this with a setup hook — a little script at .cmux/setupthat runs automatically every time a new worktree is created, from inside that new worktree. Mine does two things: symlinks the gitignored secrets from the main copy, and installs dependencies.

🔧 Developer section: what my setup hook does

There’s even a cmux init command that asks Claude to generate that setup script by reading your repo and guessing what it needs — which secrets to symlink, which package manager to use. It shows you the script, lets you edit or regenerate it, and only saves when you accept. I tweaked what it produced, but it got the shape right on the first try.

The symlink detail matters

Symlinking secrets instead of copying them means there’s still exactly one real.env.local on disk, in the main repo. Rotate a key once and every worktree sees the new value. If cmux had copied the file into each worktree, I’d have five stale copies of my credentials scattered around — more places to leak from, more places to forget to update.

The Same Tool on Both Machines

I run cmux in two places. On my Mac, it’s for the interactive stuff — building this site, poking at a feature, three tabs open while I bounce between them. On my always-on home Linux server, it’s for work that needs to keep running after I close my laptop: a long refactor on one of my bots, or an agent grinding through a big migration overnight.

The setup is identical on both — same shell function, same commands, same .cmux/setuphook committed to each repo — which is the whole point. I don’t have to remember a different workflow depending on which machine I’m on. The only real difference is that on the server I start the session inside a persistent terminal (so it survives me disconnecting), and check back on it later with cmux start <branch> to pick the conversation back up right where it left off.

When Parallel Actually Helps (and When It Doesn’t)

The honest lesson from a week of using this: parallel isn’t always better. Running three agents at once only helps when the three tasks are genuinely independent. If task B depends on task A finishing first, parallelizing them just means A finishes, and then I have to merge A into B’s branch before B’s work even makes sense — which is more coordination, not less.

Where it shines: unrelated jobs in the same repo. A CSS fix, a new writing post, and a data script — three lanes, no overlap, all done by the time I’ve finished my coffee. Or trying two approaches to the same problem in two worktrees and keeping whichever one comes out cleaner. Where it hurts: anything where I need to hold the whole thing in my head. Watching three agents at once splits my attention, and a subtle mistake in one is easier to miss when I’m context- switching between tabs. For focused, careful work, I still just run one claude in one folder like normal.

The merge is where you pay attention

Three isolated agents can’t conflict while they work — but their branches can conflict when they merge, if two of them happened to touch the same file. cmux won’t let me merge a worktree with uncommitted changes, which forced me into a good habit: get each branch committed and clean before merging, and merge them back one at a time so I can read what each one actually changed instead of trusting a big combined blob.

The Workflow, Start to Finish

Terminal — Three Agents, One Repo
# Tab 1 — kick off a bug fix
$ cmux new fix-footer
Worktree ready: .worktrees/fix-footer
Running .cmux/setup... symlinked .env.local, installed deps

# Tab 2 — draft a new post at the same time
$ cmux new new-post

# Later — check what’s in flight
$ cmux ls
.worktrees/fix-footer [fix-footer]
.worktrees/new-post [new-post]

# fix-footer is done — merge it and clean up
$ cmux merge fix-footer
Merged ‘fix-footer’ into ‘main’.
$ cmux rm fix-footer
Removed worktree and branch: fix-footer

Create, work, merge, remove — the whole lifecycle in four one-word commands.

What went fast

What needed patience

The best part isn’t the speed, though the speed is real. It’s that a whole category of annoyance just disappeared — the “I can’t start that until this one finishes” feeling. Now independent work happens independently. Three lanes, three agents, one subscription, and a clean merge at the end. I create a worktree, hand a task to an agent, and go start the next one.

← Back to all writing