tmux & Herdr¶
Terminal multiplexers keep sessions alive after you disconnect and split one terminal into windows and panes.
I used to use tmux, but have since switched to Herdr. It's much better at managing several AI coding agents side by side, and at working across remote servers from one window. The tmux setup is still further down for posterity, but I don't use it anymore.
Herdr¶
Link: herdr.dev
Herdr describes itself as an "agent multiplexer that lives in your terminal": a workspace manager for running coding agents like Claude Code in parallel panes. It has named sessions (herdr --session <name>, herdr session attach <name>) and can attach to a session on another machine over SSH with herdr --remote <ssh-target>.
My config just tones the UI down and makes it use the terminal's colours, so it inherits Ghostty's Catppuccin palette:
onboarding = false
[ui]
status_indicators = "symbols"
show_agent_labels_on_pane_borders = false
[theme]
name = "terminal"
auto_switch = false
Remote machines¶
The laptop runs the Herdr client, and any servers I work on are saved as SSH machines. They all appear in one sidebar: local workspaces plus each server's workspaces. The agent list covers every machine, so I can see at a glance which Claude Code session, wherever it's running, is waiting for an answer.
Each server runs its own Herdr server (the default session), so agents keep running there when the laptop sleeps or the connection drops. Herdr reconnects by itself, and a dropped connection to one machine doesn't affect the others.
SSH first¶
Herdr uses plain OpenSSH underneath, so everything starts with a normal ~/.ssh/config entry for each machine:
ForwardAgent yesletsgit pushover SSH and commit signing inside remote panes use the keys on the laptop. Herdr doesn't turn on forwarding by itself. Only enable it for hosts you trust.- Herdr's background connections can't answer prompts. If the key has a passphrase, load it with
ssh-addfirst, whichAddKeysToAgenthandles after the first use.
Check plain ssh <computer_name> works before involving Herdr. For how my machines reach each other from anywhere, see Homelab.
Adding and using machines¶
herdr machine add <computer_name> # installs/starts Herdr on the server if needed (asks first)
herdr machine list # saved profiles and their IDs
herdr machine status # non-interactive health check: "reachable" or not
herdr machine reconnect <computer_name> # redo SSH auth in this terminal if a machine shows "! auth"
- Switching: click a machine or workspace in the sidebar, or press
prefix+wand then use the arrow keys to move through workspaces across all machines, withEnterto jump. - Scripting:
herdr --machine <computer_name> agent listruns API commands against a saved machine without opening the UI. - One-off attach without saving a profile:
herdr --remote <computer_name>.
Claude Code integration
Install Herdr's Claude integration on each machine where Claude Code runs, not just on the Mac. It adds a small SessionStart hook to ~/.claude/ that tells Herdr which Claude session is running in which pane, so panes map to the right conversation:
Updating¶
--handoff hands the open panes over to the new server, so running agents and shells keep going through the upgrade. Afterwards, run herdr to reattach, and re-run herdr integration install claude if it says the integrations are out of date. Do this on each remote machine too, since they don't update with the Mac.
tmux¶
No longer used
This is my old tmux setup, kept for posterity. I've switched to Herdr.
Older computing clusters
TPM and many of its plugins need a fairly recent tmux. On some older computing clusters, the system tmux is far too old, and installing a new enough version yourself (without root, with old compilers and libraries) can be a real challenge.
Config lives at ~/.config/tmux/tmux.conf. Like most of my config, it lives under ~/.config rather than as ~/.tmux.conf, and note there's no dot in front of tmux.conf.
Plugins¶
Plugins are managed by TPM. Install it once, then press prefix + I inside tmux to fetch everything listed in the config:
| Plugin | What it does |
|---|---|
| tmux-sensible | Sensible defaults everyone agrees on. |
| tmux-cpu | CPU / RAM usage for the status bar. |
| tmux-resurrect | Save and restore sessions, windows and panes across reboots. |
| tmux-continuum | Saves automatically, and with @continuum-restore 'on' restores when tmux starts. |
| tmux-better-mouse-mode | Mouse scrolling that behaves. |
| tmux-menus | Popup menus for tmux actions, handy when you forget a keybinding. |
| tmux-fzf | Fuzzy-find sessions, windows, panes and commands. |
| tmux-fzf-url | Fuzzy-pick any URL visible in the pane and open it. |
The theme is catppuccin/tmux. Unlike the others it's cloned manually and loaded with a run line:
Settings worth copying¶
set -g base-index 1 # start indexing windows at 1 instead of 0
set -g history-limit 1000000 # increase history size (from 2,000)
set -g renumber-windows on # renumber all windows when any window is closed
set -g update-environment -r # pick up the newest environment variables
set-option -g mouse on
set-option -g default-shell $SHELL
set -g set-clipboard on
Linux-only bits¶
My tmux config is a chezmoi template, and a few lines only apply on Linux servers:
{{ if ne .chezmoi.os "darwin" }}
set-option -g prefix C-g
{{ end }}
{{ if ne .chezmoi.os "darwin" }}
set -as terminal-features ',ghostty*:clipboard'
set -as terminal-overrides ',ghostty*:Ms=\E]52;%p1%s;%p2%s\007'
{{ end }}
{{ if ne .chezmoi.os "darwin" }}
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",ghostty*:RGB"
{{ end }}
- Prefix
Ctrl+Gon servers. It staysCtrl+Bon the Mac. When a server's tmux is running inside the Mac's tmux, each one has its own prefix, so there's no pressingCtrl+Btwice. - OSC 52 clipboard. Tells tmux that Ghostty supports OSC 52, so copying in tmux on a server lands in the Mac's clipboard. This is the same mechanism as the Neovim clipboard.
- True colour.
tmux-256colorplus theRGBoverride, so the Catppuccin colours render properly instead of being approximated.
Full tmux.conf (chezmoi template)
# List of plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-cpu'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
set -g @plugin 'nhdaly/tmux-better-mouse-mode'
set -g @plugin 'jaclu/tmux-menus'
set -g @plugin 'sainnhe/tmux-fzf'
set -g @plugin 'wfxr/tmux-fzf-url'
set -g update-environment -r # Update the tmux environment to use the newest environmental variables
set -g base-index 1 # start indexing windows at 1 instead of 0
set -g history-limit 1000000 # increase history size (from 2,000)
set -g renumber-windows on # renumber all windows when any window is closed
# some general status bar options
# set-option -g status-position top
# set-option -g status-style bg=default
# Catpuccin options
set -g @catppuccin_flavor "macchiato" # latte, frappe, macchiato, mocha
set -g @catppuccin_window_status_style "rounded"
set -g @catppuccin_window_number_position "right"
set -g @catppuccin_window_number "#I"
set -g @catppuccin_window_text "#W"
set -g @catppuccin_window_number_color "#{@thm_lavender}"
set -g @catppuccin_window_current_number "#I"
set -g @catppuccin_window_current_text "#W"
#set -g @catppuccin_window_current_background "#{@thm_lavendar}"
set -g @catppuccin_status_left_separator " "
set -g @catppuccin_status_right_separator ""
set -g @catppuccin_status_fill "icon"
set -g @catppuccin_status_connect_separator "no"
# Load catppuccin
set -g status-right-length 80
set -g status-left ""
set -g status-right "#{E:@catppuccin_status_application}"
set -ag status-right "#{E:@catppuccin_status_directory}"
set -ag status-right "#{E:@catppuccin_status_user}"
set -ag status-right "#{E:@catppuccin_status_host}"
# Load Catppuccin
run ~/.config/tmux/plugins/catppuccin/tmux/catppuccin.tmux
# Enable automatic restore
set -g @continuum-restore 'on'
# Mouse options
set-option -g mouse on
# Use configured shell as default shell in tmux
set-option -g default-shell $SHELL
# Change the prefix key if not on a mac
{{ if ne .chezmoi.os "darwin" }}
set-option -g prefix C-g
{{ end }}
set -g set-clipboard on
# Set some options for OSC 52 clipboard
{{ if ne .chezmoi.os "darwin" }}
set -as terminal-features ',ghostty*:clipboard'
set -as terminal-overrides ',ghostty*:Ms=\E]52;%p1%s;%p2%s\007'
{{ end }}
# Then set some tmux terminal colours for macos ghostty
{{ if ne .chezmoi.os "darwin" }}
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",ghostty*:RGB"
{{ end }}
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '$XDG_CONFIG_HOME/tmux/plugins/tpm/tpm'