Master terminal multiplexing with tmux — persistent sessions, split panes, and powerful workflows for Claude Code and beyond
tmux lets you run multiple terminal sessions inside a single terminal window. Sessions persist in the background even when you disconnect — your work keeps running.
tmux runs a server process in the background. Each terminal you see is a client connected to that server. When you close your terminal, the server keeps running — you just reconnect later.
# Debian / Ubuntu
sudo apt install tmux
# Fedora / RHEL
sudo dnf install tmux
# Arch
sudo pacman -S tmux
# Homebrew
brew install tmux
# Inside WSL (Ubuntu)
sudo apt install tmux
$ tmux -V
tmux 3.4
# Start a new session
$ tmux
# Start a named session
$ tmux new -s myproject
# You're now inside tmux!
# Notice the green status bar
# at the bottom of the terminal
If you see no server running when you try to attach, it just means there are no active sessions yet — start one with tmux new.
Every tmux keybinding starts with a prefix key, followed by the actual command key. The default prefix is:
Ctrl + b
Press Ctrl+b, release both keys, then press the command key.
# Split vertically (side by side)
Ctrl+b then %
# Split horizontally (top and bottom)
Ctrl+b then "
The prefix is not held down while pressing the command key — it's a two-step sequence.
Many users remap the prefix to Ctrl+a (closer to the home row) in their .tmux.conf:
# ~/.tmux.conf
unbind C-b
set -g prefix C-a
bind C-a send-prefix
| Keys | Action |
|---|---|
Ctrl+b | Prefix (default) |
Prefix ? | List all keybindings |
Prefix : | Command prompt |
Prefix t | Show clock |
Throughout this presentation:
Prefix means Ctrl+b (or your custom prefix)Prefix x means: press prefix, release, then press xC-b is shorthand for Ctrl+bM-x means Alt+x# New session (auto-named 0, 1, 2...)
tmux new
# Named session
tmux new -s project-alpha
# New session starting in a directory
tmux new -s api -c ~/code/api
# Detach from current session
Prefix d
# List all sessions
tmux ls
# Reattach to a named session
tmux attach -t project-alpha
# Shorthand
tmux a -t project-alpha
Detaching does not stop processes — everything keeps running in the background.
# Interactive session picker
Prefix s
# Next / previous session
Prefix ( → previous
Prefix ) → next
# Switch by name from command line
tmux switch -t ops
# Rename current session
Prefix $
# Kill a session
tmux kill-session -t old-project
# Kill all sessions except current
tmux kill-session -a
# Kill the tmux server entirely
tmux kill-server
Windows are tabs within a session. Each window occupies the full terminal and can contain one or more panes. The status bar at the bottom shows your window list.
# Create a new window
Prefix c
# Close the current window
Prefix &
# (confirms: kill window? y/n)
# Or just exit the shell
$ exit
# Rename current window
Prefix ,
# Then type the new name and
# press Enter
Named windows make it easy to identify what each tab is for: editor, server, claude, etc.
| Keys | Action |
|---|---|
Prefix 0-9 | Switch to window by number |
Prefix n | Next window |
Prefix p | Previous window |
Prefix l | Last (most recent) window |
Prefix w | Interactive window picker |
Prefix f | Find window by name |
# Move window to a new index
Prefix .
# Then type the new index number
# Swap window positions
tmux swap-window -s 2 -t 0
# Move current window left/right
# (add to .tmux.conf)
bind -r < swap-window -t -1
bind -r > swap-window -t +1
# Horizontal split (top / bottom)
Prefix "
# Vertical split (left / right)
Prefix %
Splits always divide the currently focused pane.
| Keys | Action |
|---|---|
Prefix ↑↓←→ | Move to adjacent pane |
Prefix o | Cycle to next pane |
Prefix ; | Toggle to last active pane |
Prefix q | Show pane numbers (press number to jump) |
# Close current pane
Prefix x
# (confirms: kill pane? y/n)
# Or just exit the shell
$ exit
# Resize with prefix + arrow (hold)
Prefix Ctrl+↑ → taller
Prefix Ctrl+↓ → shorter
Prefix Ctrl+← → narrower
Prefix Ctrl+→ → wider
# Or from the command prompt
Prefix :
resize-pane -D 10 # 10 rows down
resize-pane -R 20 # 20 cols right
# Zoom: toggle pane fullscreen
Prefix z
# Press again to un-zoom
# Cycle through built-in layouts
Prefix Space
# Preset layouts
Prefix M-1 → even-horizontal
Prefix M-2 → even-vertical
Prefix M-3 → main-horizontal
Prefix M-4 → main-vertical
Prefix M-5 → tiled
# Enter copy mode
Prefix [
# You can now scroll up/down
# with arrow keys or Page Up/Down
# Exit copy mode
q or Escape
Copy mode is how you scroll back through terminal output in tmux. Without it, scrolling doesn't work as expected.
# In copy mode:
/ → search forward
? → search backward
n → next match
N → previous match
Extremely useful for finding error messages in long Claude Code output.
# In copy mode (emacs keys):
Ctrl+Space → start selection
M-w → copy selection
# In copy mode (vi keys):
Space → start selection
Enter → copy selection
# Paste
Prefix ]
# ~/.tmux.conf
setw -g mode-keys vi
# Now copy mode uses vi motions:
# h j k l → move cursor
# v → start selection
# y → yank (copy)
# / → search
# Default is 2000 lines
# Increase in .tmux.conf:
set -g history-limit 50000
# ~/.tmux.conf
# Remap prefix to Ctrl+a
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# Enable mouse support
set -g mouse on
# Start windows and panes at 1
set -g base-index 1
setw -g pane-base-index 1
# Vi copy mode
setw -g mode-keys vi
# Large scrollback
set -g history-limit 50000
# Faster key repetition
set -sg escape-time 0
# True colour support
set -g default-terminal "tmux-256color"
set -ag terminal-overrides \
",xterm-256color:RGB"
# Split with | and -
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %
The -c flag opens the new pane in the same directory as the current pane.
# Navigate panes with h j k l
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# Add to .tmux.conf:
bind r source-file ~/.tmux.conf \;\
display "Config reloaded!"
# Then reload with:
Prefix r
The bar at the bottom of every tmux session has three sections:
# Colours
set -g status-style "bg=#10101a,fg=#8888a8"
# Left: session name
set -g status-left \
"#[fg=#0a0a0f,bg=#f5a623,bold] #S "
set -g status-left-length 20
# Right: date and time
set -g status-right \
"#[fg=#4ecb8d] %H:%M #[fg=#8888a8]%d-%b"
set -g status-right-length 30
# Window tabs
setw -g window-status-format \
" #I:#W "
setw -g window-status-current-format \
"#[fg=#0a0a0f,bg=#a78bfa,bold] #I:#W "
| Variable | Value |
|---|---|
#S | Session name |
#I | Window index |
#W | Window name |
#P | Pane index |
#H | Hostname |
#T | Pane title |
%H:%M | Time (24h) |
%d-%b | Date (e.g., 04-Apr) |
# Active pane border colour
set -g pane-active-border-style \
"fg=#f5a623"
# Inactive pane border
set -g pane-border-style \
"fg=#2a2a3a"
# ~/.tmux.conf
set -g mouse on
With mouse on, you can:
When mouse mode is on, click-and-drag selects text in tmux’s copy buffer, not the system clipboard. To copy to the system clipboard, hold Shift while selecting.
# Alternatively, pipe to clipboard
# Linux (X11):
bind -T copy-mode-vi y send -X \
copy-pipe-and-cancel "xclip -sel clip"
# macOS:
bind -T copy-mode-vi y send -X \
copy-pipe-and-cancel "pbcopy"
| Task | Mouse | Keyboard |
|---|---|---|
| Select pane | Click | Prefix ↑↓←→ |
| Resize pane | Drag border | Prefix Ctrl+arrow |
| Scroll | Scroll wheel | Prefix [ |
| Switch window | Click tab | Prefix 0-9 |
tmux sessions persist independently of your terminal connection. If your SSH drops, your laptop goes to sleep, or you accidentally close a tab — everything keeps running.
# Connect to remote server
$ ssh user@server
# Start (or reattach) tmux session
$ tmux new -s work
# ... or ...
$ tmux a -t work
# Do your work...
# Connection drops? No problem.
# Reconnect later:
$ ssh user@server
$ tmux a -t work
# Everything is exactly as you left it
Perfect for tasks that take hours:
Start the process in tmux, detach with Prefix d, and come back whenever you want.
# Add to your .bashrc or .zshrc:
# Auto-attach to tmux on SSH login
if [ -n "$SSH_CONNECTION" ] && \
[ -z "$TMUX" ]; then
tmux attach -t ssh || tmux new -s ssh
fi
Now you always land in a tmux session when connecting via SSH.
# Create a session for your project
tmux new -s myproject -c ~/code/myproject
# Start Claude Code
claude
# Split a pane to keep a shell handy
Prefix %
# Now you have Claude on the left,
# shell on the right
| Action | How |
|---|---|
| Switch to shell pane | Prefix → |
| Zoom into Claude pane | Prefix z |
| Scroll Claude output | Prefix [ |
| Detach & let it run | Prefix d |
Claude Code supports a headless (non-interactive) mode via the -p flag — perfect for fire-and-forget tasks in tmux:
# Send a prompt non-interactively
claude -p "Refactor the auth module \
to use JWT tokens"
# With auto-accept for tool use
claude -p "Add unit tests for utils.ts" \
--allowedTools Edit,Write,Bash
# Create a new window for a task
Prefix c
# Run Claude headless
claude -p "Review all Python files in \
src/ for security issues and write \
a report to SECURITY_REVIEW.md" \
--allowedTools Read,Write,Glob,Grep
# Detach and let it work
Prefix d
# Come back later to check the result
tmux a
# Window 0: Claude on backend
claude -p "Add input validation \
to all API endpoints"
# Window 1: Claude on frontend
claude -p "Add loading states \
to all data-fetching components"
# Window 2: Claude on tests
claude -p "Write integration tests \
for the payment flow"
Each window runs an independent Claude instance, working on a different part of the codebase simultaneously.
# Create sessions for each project
tmux new -s api -c ~/code/api -d
tmux new -s frontend -c ~/code/app -d
tmux new -s infra -c ~/code/terraform -d
# The -d flag creates without attaching
# Now switch between them:
Prefix s → session picker
Prefix ( → previous session
Prefix ) → next session
Each session starts in its own directory, with its own windows and panes.
Keep session names short and descriptive:
api — backend REST APIweb — frontend applicationops — infrastructure / DevOpsdb — database migrations#!/bin/bash
# ~/bin/dev-start.sh
# API session
tmux new -s api -c ~/code/api -d
tmux send-keys -t api "claude" Enter
# Frontend session
tmux new -s web -c ~/code/app -d
tmux send-keys -t web "npm run dev" Enter
tmux split-window -t web -h \
-c ~/code/app
tmux send-keys -t web "claude" Enter
# Attach to the API session
tmux attach -t api
Run ./dev-start.sh once and your entire dev environment is ready.
The send-keys command types text into a pane programmatically — ideal for automation scripts that launch servers, editors, or Claude Code.
# Send to a specific session:window
tmux send-keys -t api:0 "make test" Enter
tmux new -s name | New session |
tmux a -t name | Attach |
tmux ls | List sessions |
Prefix d | Detach |
Prefix s | Session picker |
Prefix $ | Rename session |
Prefix c | New window |
Prefix , | Rename window |
Prefix n | Next window |
Prefix p | Previous window |
Prefix 0-9 | Go to window # |
Prefix & | Kill window |
Prefix % | Split vertical |
Prefix " | Split horizontal |
Prefix ↑↓←→ | Navigate |
Prefix z | Zoom toggle |
Prefix x | Kill pane |
Prefix Space | Cycle layouts |
Prefix [ | Enter copy mode |
/ or ? | Search fwd / back |
Space | Start selection (vi) |
Enter | Copy selection (vi) |
Prefix ] | Paste |
q | Exit copy mode |
tmux ls | List sessions |
tmux a -t name | Attach to session |
tmux kill-session -t x | Kill session |
tmux kill-server | Kill everything |
tmux send-keys | Send input to pane |
Prefix : | Command prompt |
# Share a session across terminals
# (each can view different windows)
tmux new -s main
# In another terminal:
tmux new -t main -s viewer
# Both see the same session,
# but can look at different windows
# Break pane into its own window
Prefix !
# Join a pane from another window
# (from command prompt):
Prefix :
join-pane -s 2.1 # source win:pane
join-pane -t 0 # target window
# Type in ALL panes simultaneously
Prefix :
setw synchronize-panes on
# Useful for running the same command
# on multiple servers at once
# Turn off:
setw synchronize-panes off
# Capture visible pane content
tmux capture-pane -p > output.txt
# Capture entire scrollback
tmux capture-pane -pS - > full.txt
# Pipe a pane's output to a file
tmux pipe-pane -o "cat >> ~/log.txt"
# Stop piping:
tmux pipe-pane
Great for saving Claude Code's responses for later review.
# Pass env vars to new sessions
tmux new -s work \
-e "NODE_ENV=development" \
-e "DEBUG=app:*"
# Update environment in session
tmux set-environment -t work \
API_KEY "sk-..."
# Show session environment
tmux show-environment -t work
# Add to .tmux.conf:
set -g default-terminal "tmux-256color"
set -ag terminal-overrides \
",xterm-256color:RGB"
# Make sure your terminal emulator
# supports true colour (most do)
Ctrl+b, not Ctrl+B (no Shift)tmux show -g prefixPrefix Prefix key to send to inner session# SSH into server with its own tmux?
# Send prefix to inner session:
Prefix Prefix key
# Or remap inner session to C-a
# and keep outer as C-b
# "sessions should be nested" error
# You're already in tmux! Either:
unset TMUX # then attach
# or use session switching instead:
Prefix s
# "no sessions" error
tmux ls # confirms no sessions
tmux new -s fresh # start one
Prefix z to zoom the Claude pane to full screenTERM=xterm-256color if colours are wrongset -g history-limit 50000# If a pane is unresponsive:
Prefix x → kill-pane (confirm)
# Nuclear option:
tmux kill-pane -t 2
# ~/.tmux.conf — opinionated starter
# ── Prefix ──
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# ── General ──
set -g mouse on
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
set -sg escape-time 0
set -g history-limit 50000
setw -g mode-keys vi
# ── Terminal ──
set -g default-terminal "tmux-256color"
set -ag terminal-overrides \
",xterm-256color:RGB"
# ── Splits ──
bind | split-window -h \
-c "#{pane_current_path}"
bind - split-window -v \
-c "#{pane_current_path}"
unbind '"'
unbind %
# ── Navigation ──
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# ── Resize ──
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# ── Reload ──
bind r source-file ~/.tmux.conf \;\
display "Config reloaded!"
# ── Status Bar ──
set -g status-style "bg=#10101a,fg=#8888a8"
set -g status-left \
"#[fg=#0a0a0f,bg=#f5a623,bold] #S "
set -g status-right \
"#[fg=#4ecb8d] %H:%M #[fg=#8888a8]%d-%b"
setw -g window-status-format " #I:#W "
setw -g window-status-current-format \
"#[fg=#0a0a0f,bg=#a78bfa,bold] #I:#W "
# ── Borders ──
set -g pane-active-border-style \
"fg=#f5a623"
set -g pane-border-style "fg=#2a2a3a"
tmux transforms your terminal from a single, fragile window into a persistent, multi-pane workspace. Combined with Claude Code, it enables powerful workflows — fire-and-forget tasks, parallel agents, and uninterrupted long-running sessions.
man tmux — comprehensive and well-writtenclaude.ai.tmux.conf with the config from slide 19