How to Run Multiple Claude Code Sessions in tmux (and Why 3 Beats 5)

How to Run Multiple Claude Code Sessions in tmux (and Why 3 Beats 5)

# claudecode# ai# productivity# linux
How to Run Multiple Claude Code Sessions in tmux (and Why 3 Beats 5)Alan West

A .tmux.conf, worktree spawner, send-keys script and Stop hook for done alerts, plus why 5 agents drain your shared Pro/Max limit 5x faster.

Anthropic's own docs tell you to start a team of Claude Code agents at 3 to 5, and they say outright that "three focused teammates often outperform five scattered ones." Most of the "I run 12 agents in parallel" posts skip that line.

I run multiple Claude Code sessions in tmux every day. tmux is free, it's been around since 2007, and it covers what parallel agents need: one session per git worktree, send-keys so scripts can drive agents, and detach/reattach so a job on a remote box keeps going when SSH drops. Below is my .tmux.conf, a spawner script, a send-keys script, a hook that tells you when an agent is done, and the point where adding agents starts slowing you down.

Why tmux works for parallel Claude Code sessions

Claude Code is an interactive TUI. tmux keeps TUIs alive on a server and doesn't care which client is looking at them. The crystl guide that kicked off the HN thread has a survival table that covers it:

Event Agents keep running?
Close the terminal window yes
Detach client yes
SSH drops yes
kill-session / kill-server no
Reboot no

Two HN commenters called that guide an ad for crystl ("essentially an ad for crystl," in one's words), and they have a point: right after its "Where tmux stops" section comes "Where crystl picks up," which is a product pitch. The tmux commands in it are fine, though, so I've borrowed the useful ones and left the pitch out.

Step 1: one worktree per agent

Two agents editing one checkout will overwrite each other's work. Anthropic's agent teams page is blunt about it: "Two teammates editing the same file leads to overwrites." The fix is a git worktree per agent, and Claude Code now has it built in:

claude --worktree feature-auth      # or: claude -w feature-auth
Enter fullscreen mode Exit fullscreen mode

According to the worktree docs, this creates .claude/worktrees/feature-auth/ on a new branch worktree-feature-auth. A few things that will trip you up:

  • Add .claude/worktrees/ to .gitignore, or your main checkout fills up with untracked noise.
  • A worktree is a fresh checkout, so .env isn't there. Put the gitignored files you need into a .worktreeinclude file (it uses .gitignore syntax) and they get copied in.
  • Dependencies aren't copied either. Every worktree needs its own npm install or equivalent.
  • Interactive --worktree exits with an error if you've never accepted the trust dialog in that repo. Run plain claude there once first.

There's also a native tmux flag: claude -w feature-auth --tmux creates a tmux session for the worktree. If iTerm2 is available it uses native panes instead, and --tmux=classic forces real tmux (CLI reference). That's handy for a single agent. For five, I'd rather have a script I control.

Step 2: a .tmux.conf for agents

This is the crystl config plus aggressive-resize. The first line matters most: Claude streams a lot of output, and the default scrollback runs out quickly.

set -g history-limit 100000
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",*256col*:Tc"
set -g mouse on
set -g allow-rename off
set-window-option -g automatic-rename off
set -g base-index 1
set-window-option -g pane-base-index 1
set -g renumber-windows on
set-window-option -g monitor-activity on
set -g visual-activity off
set -g status-interval 5
set -sg escape-time 10
set-window-option -g aggressive-resize on
bind -n M-h select-pane -L
bind -n M-j select-pane -D
bind -n M-k select-pane -U
bind -n M-l select-pane -R
bind r source-file ~/.tmux.conf \; display-message "config reloaded"
Enter fullscreen mode Exit fullscreen mode

allow-rename off stops agents from retitling your windows, so a window named auth stays auth. escape-time 10 gets rid of the lag on Esc, and you'll be pressing Esc a lot to interrupt Claude. If you run tmux on your laptop and again on the devbox, change the prefix on one of them (set -g prefix C-a) so the two don't fight over it.

Step 3: spawn N agents with one command

Save this as ~/bin/agents. Each window gets one named worktree and one Claude session.

#!/usr/bin/env bash
# usage: agents <repo-dir> <name> [name...]
set -euo pipefail
repo=$1; shift
sess=agents
tmux has-session -t "$sess" 2>/dev/null || tmux new-session -d -s "$sess" -n shell -c "$repo"
for name in "$@"; do
  tmux new-window -t "$sess" -n "$name" -c "$repo"
  tmux send-keys -t "$sess:$name" "claude -w $name" Enter
done
if [ -n "${TMUX:-}" ]; then tmux switch-client -t "$sess"; else tmux attach -t "$sess"; fi
Enter fullscreen mode Exit fullscreen mode

agents ~/code/api auth billing flaky-tests gives you three windows and three branches, with nothing shared in the file tree. The last line switches instead of attaching if you're already inside tmux, because a nested attach refuses to run.

Step 4: drive agents from scripts with send-keys

Typing a prompt into a pane from a script looks trivial, and it's where most people's first attempt fails. Two gotchas from the crystl guide: tmux treats bare words like Enter as key names, and an Enter sent in the same frame as the text can get swallowed. Send the text literally, wait a moment, then press Enter:

#!/usr/bin/env bash
# usage: ask <window> "<prompt>"
target="agents:$1"
tmux send-keys -t "$target" -l "$2"
sleep 0.3
tmux send-keys -t "$target" Enter
Enter fullscreen mode Exit fullscreen mode

ask billing "run the test suite and fix what fails" works now. tmux send-keys -t agents:billing C-c interrupts the agent. To read what an agent printed without attaching, tmux capture-pane -p -J -S -200 -t agents:billing gives you the last 200 lines with wrapped lines joined.

Step 5: stop staring at panes

This is where plain tmux gets weak. The crystl guide suggests monitor-silence 30, then admits silence is "a proxy for done, not a report of it." Its status-bar script greps captured panes for strings like esc to interrupt, and those strings change between Claude Code versions.

You don't have to guess, because Claude Code already reports when it's done. The hooks docs describe a Stop hook that fires "when Claude finishes responding," and a Notification hook whose matchers include permission_prompt and idle_prompt. Hook commands inherit the pane's environment, so they can call tmux. Here's my version in ~/.claude/settings.json:

{
  "hooks": {
    "Stop": [
      { "hooks": [ { "type": "command",
        "command": "[ -z \"$TMUX\" ] || tmux display-message -d 5000 -t \"$TMUX_PANE\" 'claude done: #{window_name}'" } ] }
    ],
    "Notification": [
      { "matcher": "permission_prompt",
        "hooks": [ { "type": "command",
        "command": "[ -z \"$TMUX\" ] || tmux display-message -d 5000 -t \"$TMUX_PANE\" 'claude needs you: #{window_name}'" } ] }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

I wrote the test as [ -z ... ] || on purpose: with [ -n ... ] &&, the hook exits 1 whenever you run Claude outside tmux, and Claude Code counts any exit code other than 0 or 2 as a non-blocking hook error. The -d delay needs a reasonably recent tmux, so check yours with tmux -V. Since the signal comes from Claude Code and nothing scrapes pane text, a UI redesign won't break it.

Step 6: reattach over SSH so long jobs survive

ssh devbox -t tmux new-session -A -s agents
Enter fullscreen mode Exit fullscreen mode

-A attaches if the session exists and creates it if it doesn't, so the same command works on the first connection and the fiftieth. Close the laptop, change trains, reconnect, and the agents are where you left them. On flaky connections, mosh helps. A reboot still kills everything, and tmux scrollback goes with the server.

How many Claude Code agents is too many?

This is the part I'll argue about. Every agent you add costs you in three places.

The first is your attention. Every agent eventually stops to ask you something. On HN, benfrancom said their goal is "2 active sessions to avoid context switching," and that running "upwards of a dozen" was draining. Anthropic's own guidance is 3 to 5 teammates, and they note that past a certain point "additional teammates don't speed up work proportionally."

Then merge conflicts. Worktrees keep agents out of each other's files while they're working, but they do nothing for you at merge time. Five branches that each touched routes.ts means five merges that you resolve yourself.

Rate limits are the hard cap. Anthropic's plan docs say Pro and Max limits "are shared across Claude and Claude Code," with both a five-hour session limit and a weekly limit. Five agents split that one allowance and run through it about five times faster. The agent teams page says that token costs "scale linearly" with the number of teammates.

Agents What usually happens
1 You wait on Claude
2–3 Claude waits on you about half the time. This is the sweet spot
4–5 Your review queue becomes the bottleneck and merges hurt
6+ You run into the five-hour limit and spend the afternoon resolving conflicts

The table is my opinion; the costs behind it come from the sources above.

tmux or Claude Code's agent view?

Claude Code now ships agent view (claude agents, still a research preview). It runs background sessions under a supervisor process, sorts them into groups like Needs input, Working and Completed, and keeps them running when you close the terminal. That covers the status problem crystl is selling a fix for, and it costs nothing. A shutdown stops running sessions there too, but unlike a dead tmux pane, attaching or replying restarts the session from its saved conversation.

I still use tmux, for two reasons. It doesn't care which agent runs in a pane, and one HN commenter runs Codex, Claude Code and Pi side by side on the same task. And send-keys plus capture-pane is a scripting API I already know. If you only use Claude Code on your laptop, try agent view first.

So how many Claude Code sessions do you run in parallel before it stops being faster? Post your number and the thing that capped it, whether that was rate limits, merges or your own attention. I'm betting most of you land at 3.

Sources