terminal craft · 8 min read · 2026-07-10

Claude Code + tmux: the missing manual

A coding agent mid-refactor is the worst possible process to lose to a closed terminal window. tmux is the standard fix, but the generic tmux tutorials skip everything agent-specific: how to lay out one window per model, how to drive sessions from scripts, and the two gotchas (PATH and window names) that bite anyone who automates this. This is the manual we wished existed, learned from building a product on exactly this stack.

Why agents need tmux at all

Claude Code and Codex are attached to your terminal. Close the window, drop the SSH connection, or let the laptop sleep through a network change, and the agent process dies mid-task, taking its in-flight work with it. tmux breaks that coupling: the agent runs inside a tmux server that survives your terminal, and you attach and detach at will. The payoffs for agent work specifically:

The garage pattern: one session, one window per model

Resist the urge to make a new tmux session per agent. One named session with one window per agent is easier to attach, list, and clean up:

tmux new-session -d -s garage -n opus
tmux send-keys -t garage:opus 'claude --model opus' C-m

tmux new-window -t garage -n haiku
tmux send-keys -t garage:haiku 'claude --model haiku' C-m

tmux new-window -t garage -n codex
tmux send-keys -t garage:codex 'codex' C-m

tmux attach -t garage

Note that each agent is launched with its model pinned via --model. That's deliberate, and it's what Anthropic's own docs recommend for running different models at the same time: per-terminal pinning rather than /model switching. Jump between agents with Ctrl-b n, Ctrl-b p, or Ctrl-b w for the picker.

Reattaching from anywhere

# is the garage running?
tmux has-session -t garage 2>/dev/null && tmux attach -t garage

# from another machine, over ssh
ssh dev-box -t 'tmux attach -t garage || tmux new -s garage'

The || tmux new idiom gives you attach-or-create in one line. The only thing tmux won't survive is a reboot of the machine running the server; for always-on agents, put the garage on a box that stays up.

The gotchas nobody documents

1. GUI apps can't find tmux

Anything launched outside a login shell (a macOS app, a launchd job, some CI runners) gets a minimal PATH that does not include Homebrew. tmux resolves fine in your terminal and fails with "command not found" from the app. If you script tmux from anything GUI-launched, probe the real locations instead of trusting PATH:

for bin in /opt/homebrew/bin/tmux /usr/local/bin/tmux /usr/bin/tmux; do
  [ -x "$bin" ] && TMUX_BIN="$bin" && break
done

We ship exactly this probe in Model Shift because it's the number-one support issue for any tmux-wrapping app on macOS.

2. Window names are not identifiers

tmux happily lets two windows share a name, and windows renumber when others close. Scripts that target garage:opus by name will eventually type into the wrong agent. When you create a window programmatically, capture its immutable window ID and target that instead:

WIN_ID=$(tmux new-window -t garage -n opus -P -F '#{window_id}')
tmux send-keys -t "$WIN_ID" 'claude --model opus' C-m

IDs look like @7 and never change or collide. Names are for humans; IDs are for automation. Every serious agent launcher learns this the hard way.

3. Send-keys needs the trailing Enter

send-keys 'claude' types the text; C-m (carriage return) actually submits it. Forgetting C-m leaves a command sitting unexecuted in a window you're not looking at, which with agents means "why has nothing happened for an hour".

4. Scrollback is your agent's audit log

Default scrollback (2,000 lines) is nothing next to an agent's output. Raise it before you need it, in ~/.tmux.conf:

set-option -g history-limit 50000

When to stop hand-rolling it

Everything above is scriptable, and the script grows: probe tmux, create the garage, one window per model, track window IDs, relaunch dead agents, remember which window maps to which model. That maintenance script is, more or less, what Model Shift is. It keeps a dedicated tmux session with one window per gear, targets windows by ID, probes Homebrew paths, launches each agent with its model pinned, and puts a stick shift on top so moving between agents is a flick instead of a Ctrl-b chord. If you love the pattern but not the plumbing, that's the productized version. (It needs brew install tmux, of course.)

The garage, pre-built

Model Shift manages the tmux garage for you: one persistent, cache-safe window per model, shifted with a lever.

Get Model Shift for Mac ⇣

Further reading: How to run multiple Claude Code sessions in parallel · Every way Claude Code switches models without asking