Post

SSH-Aware Window Names in tmux with Automatic Title Detection

SSH-Aware Window Names in tmux with Automatic Title Detection

You SSH into five servers in different tmux windows, run commands, switch between them, and completely forget which window contains which host. Tab through them all, check prompts, curse quietly. Meanwhile, the tmux status bar helpfully displays “0:bash 1:bash 2:bash 3:bash”—technically accurate, completely useless.

Tmux can detect SSH connections and update window names automatically by monitoring the SSH_CLIENT environment variable and extracting hostnames from your shell prompt. Instead of “bash”, your windows display “prod-db-01”, “staging-web-02”, “dev-ansible” without any manual renaming.

This post covers the implementation: escape sequence handling for window title updates, shell integration for bash/zsh/fish, tmux configuration for status bar formatting, and the critical timing issues that cause race conditions where windows briefly show “ssh” before resolving to the hostname.

Problem Statement

The default tmux configuration displays the current command name in window titles. When connected to remote hosts via SSH, this results in all windows showing “ssh” as the window name, regardless of the destination host. This behavior creates navigation difficulties when managing multiple simultaneous SSH sessions, as each window appears identical in the status bar.

Consider a typical workflow involving connections to three different servers: production, staging, and development. Without SSH-aware window naming, the tmux status bar displays:

1
[0] ssh  [1] ssh  [2] ssh

The desired behavior displays the actual remote hostname:

1
[0] prod-server  [1] staging-server  [2] dev-server

Solution Architecture

The solution leverages two tmux features working in coordination:

  1. Conditional automatic-rename-format: Detects when SSH is running and switches the display source
  2. Terminal title escape sequences: Allows remote shells to set the pane title

When SSH is the active command, tmux displays the pane_title (set by the remote shell) instead of pane_current_command. This mechanism provides accurate hostname display without manual intervention.

tmux Configuration

Automatic Window Renaming

The following configuration enables SSH-aware automatic renaming:

1
2
3
4
set-option -g automatic-rename on
set-option -g allow-rename on
# When SSH is running, show pane_title (set by remote host), otherwise show command
set-option -g automatic-rename-format '#{?#{==:#{pane_current_command},ssh},#{pane_title},#{pane_current_command}}'

Configuration Breakdown

OptionPurpose
automatic-rename onEnables automatic window name updates based on the running command
allow-rename onPermits escape sequences to modify the pane title
automatic-rename-formatDefines the format string for automatic naming

The format string uses tmux’s conditional syntax:

1
#{?CONDITION,TRUE_VALUE,FALSE_VALUE}

The condition #{==:#{pane_current_command},ssh} evaluates to true when the current pane command equals “ssh”. When true, the window displays #{pane_title} (the terminal title set by the remote host). When false, it displays #{pane_current_command} (the local command name).

Remote Shell Configuration

For the pane_title to contain useful information, the remote host must set the terminal title. This requires configuring the shell to emit escape sequences that update the terminal title.

Terminal Title Escape Sequence

The standard escape sequence for setting the terminal title:

1
\033]0;TITLE\007

Or using the alternative terminator:

1
\033]0;TITLE\033\\

Where TITLE is the desired window/pane title string.

Bash Configuration

Add the following to ~/.bashrc on each remote host:

1
2
3
4
5
6
# Set terminal title to user@hostname
case "$TERM" in
    xterm*|rxvt*|screen*|tmux*)
        PROMPT_COMMAND='printf "\033]0;%s@%s\007" "${USER}" "${HOSTNAME%%.*}"'
        ;;
esac

For a more detailed title including the current directory:

1
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'

Zsh Configuration

Add the following to ~/.zshrc on each remote host:

1
2
3
4
# Set terminal title before each prompt
precmd() {
    print -Pn "\033]0;%n@%m\007"
}

For directory inclusion:

1
2
3
precmd() {
    print -Pn "\033]0;%n@%m:%~\007"
}

Fish Configuration

Add the following to ~/.config/fish/config.fish on each remote host:

function fish_title
    printf "%s@%s" $USER (hostname -s)
end

Status Bar SSH Indicator

Beyond window naming, a visual SSH indicator in the status bar provides immediate awareness of remote connections. The following configuration displays “SSH” in a highlighted color when the active pane runs an SSH session:

1
#{?#{==:#{pane_current_command},ssh},#[fg=#f6c177 bold]SSH #[default],}

Integration with Status-Right

A complete status-right configuration incorporating the SSH indicator:

1
set-option -g status-right '#{?#{==:#{pane_current_command},ssh},#[fg=#f6c177 bold]SSH #[default],}#[fg=#9ccfd8]%H:%M#[default]'

This displays:

  • “SSH” in amber/orange (#f6c177) when connected to a remote host
  • Current time in cyan (#9ccfd8)

Advanced Status Bar Integration

Combining Multiple Status Elements

A comprehensive status bar configuration can incorporate SSH detection alongside other contextual information:

1
2
3
4
5
6
# Status bar with SSH indicator, git branch, and virtualenv
set-option -g status-right '\
#{?#{==:#{pane_current_command},ssh},#[fg=#f6c177 bold]SSH #[default],}\
#(cd #{pane_current_path} && git branch --show-current 2>/dev/null | sed "s/.*/[&] /")\
#{?VIRTUAL_ENV,#[fg=#c4a7e7](venv)#[default] ,}\
#[fg=#9ccfd8]%H:%M#[default]'

This configuration displays (when applicable):

  • SSH indicator for remote connections
  • Current git branch in brackets
  • Virtual environment indicator
  • Current time

Status Element Order

The recommended element order from left to right:

  1. SSH indicator (connection context)
  2. Git branch (repository context)
  3. Virtual environment (Python context)
  4. Date/time (temporal context)

This ordering presents the most relevant contextual information first.

Window Status Format

The window status format can also incorporate SSH awareness:

1
2
set-option -g window-status-format '#I:#W#{?#{==:#{pane_current_command},ssh},*,}'
set-option -g window-status-current-format '#[fg=#ebbcba,bold]#I:#W#{?#{==:#{pane_current_command},ssh},*,}#[default]'

This appends an asterisk to window names running SSH sessions, providing a quick visual scan capability.

Troubleshooting

Window Name Not Updating

Verify remote shell configuration by connecting and checking the terminal title:

1
2
3
ssh remote-host
# On the remote host:
printf "\033]0;TEST\007"

If the tmux window name does not change to “TEST”, check:

  • allow-rename is set to on
  • The remote terminal type supports title setting
  • No conflicting shell configuration overrides the title

Pane Title Shows Incorrect Information

The pane_title retains its value from the last escape sequence received. If disconnecting from SSH leaves an old hostname:

1
2
# Force pane title update from local shell
printf "\033]0;%s\007" "$(hostname)"

Add this to the local shell configuration to reset the title when SSH sessions end.

TERM Variable Considerations

Some remote servers may not set the terminal title based on the $TERM value. Ensure the terminal type is recognized:

1
2
3
4
# Check current TERM on remote host
echo $TERM

# Should be one of: xterm-256color, screen-256color, tmux-256color

If necessary, configure SSH to request a specific terminal type:

1
2
3
# ~/.ssh/config
Host *
    SetEnv TERM=xterm-256color

Complete Configuration Reference

tmux.conf

1
2
3
4
5
6
7
8
9
10
11
12
# Window naming
set-option -g automatic-rename on
set-option -g allow-rename on
set-option -g automatic-rename-format '#{?#{==:#{pane_current_command},ssh},#{pane_title},#{pane_current_command}}'

# Status bar
set-option -g status-right-length 100
set-option -g status-right '\
#{?#{==:#{pane_current_command},ssh},#[fg=#f6c177 bold]SSH #[default],}\
#(cd #{pane_current_path} && git branch --show-current 2>/dev/null | sed "s/.*/[&] /")\
#{?VIRTUAL_ENV,#[fg=#c4a7e7](venv)#[default] ,}\
#[fg=#9ccfd8]%H:%M#[default]'

Remote Host Shell Configuration

Bash (~/.bashrc)

1
2
3
4
5
case "$TERM" in
    xterm*|rxvt*|screen*|tmux*)
        PROMPT_COMMAND='printf "\033]0;%s@%s\007" "${USER}" "${HOSTNAME%%.*}"'
        ;;
esac

Zsh (~/.zshrc)

1
2
3
precmd() {
    print -Pn "\033]0;%n@%m\007"
}

Fish (~/.config/fish/config.fish)

function fish_title
    printf "%s@%s" $USER (hostname -s)
end

Summary

SSH-aware window naming in tmux eliminates the ambiguity of multiple “ssh” windows by displaying remote hostnames. The solution requires:

  1. Conditional automatic-rename-format in tmux configuration
  2. Terminal title escape sequences from remote shell configurations
  3. Optional status bar indicators for additional visual context

This configuration scales effectively across numerous simultaneous SSH sessions, providing clear identification without manual window renaming.

This post is licensed under CC BY 4.0 by the author.