tmux runs your AI coding agents in named, detachable sessions that last a closed terminal or a dropped SSH connection. You get one opening holding many agents, send-keys to category into any of them from a script, and capture-pane to peruse one back. That blend is why group use it.
Before you build any of it by hand, inspect the built-in path: latest versions of Claude Code can create the worktree and the tmux meeting for you alongside claude --worktree --tmux. This guide covers that first, afterward everything it doesn’t reach, afterward the item anywhere tmux itself stops.
Why tmux and agents go together
A coding delegate is a long-running procedure that wants to keep talking to a terminal. Three properties of tmux equivalent that shape:
It survives disconnection. The tmux server owns the pty, not your terminal window. Close the window, endure your SSH link, put the laptop to sleep: the delegate keeps operating and is motionless there whenever you reattach.
It holds many sessions in one window. Four agents rotate into four named sessions you toggle between alongside a keystroke, alternatively of four windows you hunt for in the app switcher.
It’s scriptable from outside. Any shell, anywhere, can category into a operating delegate or peruse its screen. No IPC to build, no API to cable up. This is the asset group build on, and it’s why tmux keeps showing up in agent-orchestration scripts.
The built-in flag, before you build anything
Claude Code ships alongside this wired up for the single-agent-on-a-branch case. Two flags, from claude --help on a latest version:
-w, --worktree [name] Create a new git worktree for this session (optionally define a name) --tmux Create a tmux meeting for the worktree (requires --worktree). Uses iTerm2 native panes whenever available; use --tmux=classic for traditional tmux.
So the entire “isolate this task, provision it its own session” move is one command:
claude --worktree --tmux # or name the worktree claude --worktree auth-refactor --tmux
Two particulars matter before you depend on it. --tmux errors without --worktree, so it’s a worktree characteristic that happens to create a session, not a broad meeting flag. And on iTerm2 it uses native panes alternatively of tmux, which is nicer to appearance at and method the tmux commands in the remainder of this leaf have nothing to nexus to. Pass --tmux=classic whenever you desire genuine tmux underneath, which you do if you scheme to manuscript against the session.
For a sole delegate on a sole branch, that’s the answer. Use it and skip ahead.
What it doesn’t do: run multiple agents in one session, lay out panes so you can observe them, let you category into a operating delegate from a script, inform you which delegate is waiting on you, or set any of this up on a distant box complete SSH. Those are the remainder of this guide, and all one is anywhere group end up penning tmux by hand.
More on the worktree fractional of that emblem in git worktrees for parallel development.
Session per project, named by project
The organizing regulation that keeps this usable: one tmux meeting per repo, named following the repo. Not per task, not per agent. Tasks arrive and go; the project is the stable thing.
# commencement a detached meeting in a project directory tmux new-session -d -s api -c ~/code/api # nexus to it (creates it if it doesn't exist) tmux new-session -A -s api -c ~/code/api
-A is attach-or-create. It makes a sole command harmless to run repeatedly, which is what you desire in a casing function:
# ~/.zshrc agent() { local dir="${1:-$PWD}" local name="$(basename "$dir" | tr . -)" tmux new-session -A -s "$name" -c "$dir" }
Session names can’t merge . or : (tmux uses them as mark separators), hence the tr.
Then tmux ls becomes a genuine inventory:
$ tmux ls api: 3 windows (created Fri Jul 31 09:12:04 2026) web: 2 windows (created Fri Jul 31 09:40:11 2026) infra: 1 windows (created Fri Jul 31 11:02:55 2026)
Add a bit additional alongside a format string:
tmux list-sessions -F '#{session_name} windows=#{session_windows} attached=#{session_attached}' A layout for observing multiple agents
Inside a session, provision all delegate its own window, named for the task:
tmux new-window -t api -n auth -c ~/code/api tmux new-window -t api -n tests -c ~/code/api
Windows are improved than panes for agents you’re not actively watching, since a opening expenses no display space. Panes are for the two or three you desire flank by flank correct now:
# divided the current opening and tile any is in it tmux split-window -h -c '#{pane_current_path}' tmux split-window -v -c '#{pane_current_path}' tmux select-layout tiled
#{pane_current_path} is uncomplicated to depart off. Without it a new pane opens in the directory the meeting started in, not the directory you’re really in, and the delegate you initiate there is pointed at the incorrect repo.
Two layouts by name: tiled for an equal grid of agents, and main-vertical for one big pane (the delegate you’re driving) alongside the remainder stacked beside it.
tmux select-layout main-vertical tmux set-window-option main-pane-width 60%
Percentage values for main-pane-width need tmux 3.2 or newer. On older builds use an complete pillar figure (main-pane-width 120). Check alongside tmux -V.
A .tmux.conf value having
These are the lines that matter for delegate activity specifically. They’re not a complete config, they’re the delta from defaults that a fleet of agents makes you want.
# agents create a lot of output, and you volition desire to scroll rear through it set -g history-limit 100000 # 24-bit colour, so delegate TUIs render the way they were designed to set -g default-terminal "tmux-256color" set -ga terminal-overrides ",*256col*:Tc" # scroll and click between panes alongside the mouse set -g mouse on # don't let a operating procedure rename the opening out from under you set -g allow-rename off set-window-option -g automatic-rename off # 1-indexed windows equivalent the figure keys on your keyboard set -g base-index 1 set-window-option -g pane-base-index 1 set -g renumber-windows on # emblem windows whose delegate produced output during you were elsewhere set-window-option -g monitor-activity on set -g visual-activity off # position row refreshes frequently adequate to be a monitor set -g status-interval 5 # no postpone whenever an agent's TUI says an escape sequence set -sg escape-time 10 # jump panes without the prefix key 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 # reload without restarting the server bind r source-file ~/.tmux.conf \; display-message "config reloaded"
Agent TUIs akin to set the terminal title, so without allow-rename off your carefully named auth opening becomes any the delegate felt akin calling itself.
escape-time 10 fixes the “my arrow keys are laggy inner the agent” complaint. The default postpone exists to disambiguate a genuine Escape key from an escape sequence, and it makes interactive TUIs awareness mushy.
Driving an delegate alongside send-keys
send-keys types into a pane as if you were at the keyboard. This is how you manuscript an delegate from cron, from a git hook, or from another agent.
# mark syntax: session:window.pane tmux send-keys -t api:auth "run the test suite and fix what fails" Enter
Three things go incorrect here, in command of how often:
Bare arguments get interpreted as key names. Enter, C-c, Escape, and Space are keys, not text. If your immediate contains one of those words as a standalone disagreement it gets sent as a keypress. Use -l to dispatch a literal string:
tmux send-keys -t api:auth -l "press Enter to continue was the old flow" tmux send-keys -t api:auth Enter
-l disables key-name lookup entirely, so the newline have to be a second call.
Semicolons end the tmux command. A trailing ; in your content is peruse as a command separator. Escape it as \;.
Agent TUIs need a attack between the content and the newline. Many delegate input boxes debounce or re-render on paste, and an Enter arriving in the identical example as the content gets swallowed. The dependable pattern:
tmux send-keys -t api:auth -l "$PROMPT" sleep 0.3 tmux send-keys -t api:auth Enter
Interrupting a runaway delegate is the identical mechanism:
tmux send-keys -t api:auth C-c Reading an delegate rear alongside capture-pane
capture-pane dumps a pane’s contents to stdout. It’s the peruse fractional of the pair.
# the apparent screen tmux capture-pane -p -t api:auth # the final 200 lines, alongside wrapped lines joined rear together tmux capture-pane -p -J -S -200 -t api:auth # the complete scrollback tmux capture-pane -p -J -S - -t api:auth # keep the color escape sequences tmux capture-pane -p -e -t api:auth
-J matters additional than it looks. Without it, a row that wrapped at your terminal width comes rear as two lines, and all grep you compose against the output is incorrect at the seams.
For a uninterrupted log fairly than a snapshot, pipe-pane streams everything a pane produces to a command:
tmux pipe-pane -o -t api:auth 'cat >> ~/agent-logs/api-auth.log' # halt it tmux pipe-pane -t api:auth
-o toggles, so operating it twice turns it off. The output is raw, escape sequences and all, so pipe it through item akin sed -E 's/\x1b\[[0-9;]*[a-zA-Z]//g' if you desire it readable later.
The status-line monitor
Every individual who runs multiple agents in tmux eventually builds this: a position row that tells you which agents are operating and which are waiting.
The scheme is #() in the position line, which runs a casing command and interpolates its output, refreshed all status-interval seconds.
set -g status-interval 5 set -g status-right '#(~/bin/tmux-agent-status) | %H:%M' set -g status-right-length 100
And the script, which capture-scrapes all pane for a sign of life:
#!/usr/bin/env bash # ~/bin/tmux-agent-status out="" while read -r target; do screen="$(tmux capture-pane -p -J -S -8 -t "$target" 2>/dev/null)" name="${target%%:*}" case "$screen" in *"Do you want"*|*"❯ 1."*) out+="⏸ $name " ;; # parked on a prompt *"esc to interrupt"*) out+="● $name " ;; # working *) out+="○ $name " ;; # idle esac done < <(tmux list-panes -a -F '#{session_name}:#{window_index}.#{pane_index}') printf '%s' "$out"
It works, and it’s value building. Be clear-eyed concerning what it’s doing: cord matching against a TUI’s rendered frame, on a five-second poll, for all pane you have open. The equivalent strings are any your delegate type happens to imprint this week.
The lighter-weight type uses tmux’s own action tracking alternatively of scraping. monitor-silence fires an vigilant whenever a pane produces no output for N seconds, which is the closest native indication to “this delegate stopped”:
set-window-option -g monitor-silence 30 set -g visual-silence on
You can suspend an act off it:
set-hook -g alert-silence 'run-shell "osascript -e \"display notification \\\"agent idle\\\"\""' Silence is a proxy for done, not a study of it. An delegate thinking difficult concerning a ample document is silent too.
Detach, reattach, and what survives what
tmux detach-client # or the prefix, afterward d tmux attach -t api tmux switch-client -t web # from inner another session tmux kill-session -t api
What survives:
| Event | Agents keep running? |
|---|---|
| Close the terminal window | yes |
| Detach the client | yes |
| SSH association drops | yes |
| tmux kill-session | no |
| tmux kill-server | no |
| Reboot | no |
| macOS “Reopen windows” following restart | no |
The tmux server is fair a procedure owned by your user. Nothing concerning tmux makes it last a reboot, and a session’s scrollback is misplaced whenever the server stops. If the copy matters, pipe-pane it to a document or use a tool that persists former on its own.
One item group trip on: a detached session’s panes are sized to the final client that was attached, or to 80x24 if there never was one. An delegate TUI rendering into an 80-column pane during you’re distant volition appearance incorrect whenever you reattach at 200 columns, until it redraws. set-window-option -g aggressive-resize on helps whenever multiple clients are attached at distinct sizes.
tmux complete SSH
This is anywhere tmux is genuinely difficult to replace. Running agents on a distant box, complete a nexus you don’t trust:
# nexus or create, in one command, alongside a tty allocated ssh devbox -t tmux new-session -A -s agents
Your association drops mid-task, you run the identical command again, and you’re rear in the identical meeting alongside the delegate motionless going. Pair it alongside mosh if your nexus is bad adequate that SSH itself keeps dying.
The nested-tmux problem: if you run tmux locally and additionally on the distant box, the two catch the identical prefix. The two fixes are a distinct prefix on the distant (set -g prefix C-a), or pressing the prefix twice, which tie C-b send-prefix gives you.
For operating agents on a device that isn’t the one in forefront of you, see remote development.
Where tmux stops
tmux is fine software. It solves multiplexing and persistence concerning as fine as those can be solved, and it has been doing it since 2007. What it doesn’t do is item particular to agents, since agents didn’t be whenever its example was designed.
No visibility into which delegate is parked. An delegate waiting on an endorsement immediate looks exactly akin an delegate thinking, which looks exactly akin an delegate that completed twenty minutes ago. All three are “a pane alongside several content in it”. The status-line hack complete exists to document complete this, and it document by scraping.
No notification whenever one finishes. monitor-silence is the nearest thing, and it fires on any quiescent pane for any reason. There is no event for “the delegate is done” since tmux has no idea what an delegate is.
Screen abrasion is brittle by construction. capture-pane gives you the rendered frame: spinners, box drawing, truncated columns, ANSI. Not what the delegate said, not which tool it called, not whether that call succeeded. Every parser you compose against it breaks whenever the delegate ships a UI change.
No shared province throughout sessions. Two agents in two tmux sessions have no way to see all other. If you desire one to peruse another’s copy or hand off work, you build that yourself, out of records and locks and polling.
Scrollback for multiple streaming agents is expensive. history-limit 100000 throughout a dozen panes of delegate output is genuine memory, held per pane for as lengthy as the server lives, and gone the instant it does. See terminal emulators for AI agents for why the rendering flank of this gets costly too.
Nothing survives a reboot. Every session, all transcript, gone.
None of these are flaws. They are the border of a tool built to multiplex shells for one individual at a keyboard.
Where crystl picks up
crystl is a macOS terminal built for the workload tmux was not shaped for: many agents at once, most of them off-screen, all one occasionally needing you.
The differences map nearly one-to-one onto the catalog above.
- Approvals exterior alternatively of getting buried. When any delegate pauses for permission, crystl floats it as a card, colour-coded by project, and you answer without switching sessions. No scraping, no polling. See floating cards.
- Agent province is a first-class signal. The agent action panel shows all session’s province at once: working, waiting on you, idle, done. That’s the item the status-line manuscript was approximating.
- Output is structured, not scraped. crystl captures all turn, tool call, and outcome as typed records, so history is searchable throughout all meeting and agents can peruse all other’s transcripts without parsing ANSI.
- Sessions are organized by project, and they persist. Projects are gems, sessions inner them are shards, and former survives decision a opening or restarting the Mac. More in multitasking.
- Parallel activity on one repo is isolated. Isolated shards are backed by genuine git worktrees, so two agents on the identical repo don’t collide. See parallel sessions.
The recommendation: keep tmux. It’s motionless the correct answer for distant boxes, for long-running processes on servers, and for item anywhere the SSH nexus is the susceptible part. Use it for that. When the item you’re managing is six agents that all need a decision from you at an unpredictable moment, the issue stopped being multiplexing.
More on the organizing flank of this in managing multiple AI coding sessions, and on keeping agents operating fairly than idle in running AI coding agents for longer.