tmux hooks allow you to automatically execute commands when specific events occur. Hooks enable powerful automation and customization of tmux behavior.
Understanding Hooks
Hooks are commands that run automatically in response to tmux events. From options-table.c:1552-1620, tmux defines hooks as session-level options that are arrays of commands.
Hook Definition
The hook macros from options-table.c:236-261 define three types:
// Session hooks
OPTIONS_TABLE_HOOK (hook_name, default_value)
// Window hooks
OPTIONS_TABLE_WINDOW_HOOK (hook_name, default_value)
// Pane hooks
OPTIONS_TABLE_PANE_HOOK (hook_name, default_value)
All hooks are array options with scope-specific visibility.
Setting Hooks
Use set-hook or set-option to configure hooks:
# Set a hook
set-hook [-agpRuw] [-t target] hook-name command
# Using set-option
set -g after-new-window 'display "New window created"'
Flags :
-a: Append to hook (run after existing commands)
-g: Set globally
-t: Target specific session/window/pane
-u: Unset/remove hook
-R: Run the hook immediately
Available Hooks
From options-table.c:1552-1620, here are all available hooks:
Command Hooks
These hooks run after specific commands:
# After commands
set-hook -g after-bind-key 'display "Key bound"'
set-hook -g after-capture-pane 'display "Pane captured"'
set-hook -g after-copy-mode 'display "Left copy mode"'
set-hook -g after-display-message ''
set-hook -g after-display-panes ''
set-hook -g after-kill-pane ''
set-hook -g after-list-buffers ''
set-hook -g after-list-clients ''
set-hook -g after-list-keys ''
set-hook -g after-list-panes ''
set-hook -g after-list-sessions ''
set-hook -g after-list-windows ''
set-hook -g after-load-buffer ''
set-hook -g after-lock-server ''
set-hook -g after-new-session 'display "Session created: #{session_name}"'
set-hook -g after-new-window 'display "Window #{window_index} created"'
set-hook -g after-paste-buffer ''
set-hook -g after-pipe-pane ''
set-hook -g after-queue ''
set-hook -g after-refresh-client ''
set-hook -g after-rename-session ''
set-hook -g after-rename-window ''
set-hook -g after-resize-pane ''
set-hook -g after-resize-window ''
set-hook -g after-save-buffer ''
set-hook -g after-select-layout ''
set-hook -g after-select-pane ''
set-hook -g after-select-window ''
set-hook -g after-send-keys ''
set-hook -g after-set-buffer ''
set-hook -g after-set-environment ''
set-hook -g after-set-hook ''
set-hook -g after-set-option ''
set-hook -g after-show-environment ''
set-hook -g after-show-messages ''
set-hook -g after-show-options ''
set-hook -g after-split-window 'display "Pane split"'
set-hook -g after-unbind-key ''
Alert Hooks
These hooks run when alerts are triggered:
set-hook -g alert-activity 'display "Activity in #{window_name}"'
set-hook -g alert-bell 'display "Bell in #{window_name}"'
set-hook -g alert-silence 'display "Silence in #{window_name}"'
Client Hooks
These hooks run for client events:
set-hook -g client-active 'display "Client activated"'
set-hook -g client-attached 'display "Client attached"'
set-hook -g client-detached 'display "Client detached"'
set-hook -g client-focus-in 'display "Client focused"'
set-hook -g client-focus-out 'display "Client unfocused"'
set-hook -g client-resized 'display "Client resized"'
set-hook -g client-session-changed 'display "Session changed"'
set-hook -g client-light-theme 'source-file ~/.tmux-light.conf'
set-hook -g client-dark-theme 'source-file ~/.tmux-dark.conf'
Command Error Hook
set-hook -g command-error 'display "Command failed: #{command_error}"'
Pane Hooks
These hooks run for pane events:
set-hook -g pane-died 'display "Pane #{pane_id} died"'
set-hook -g pane-exited 'display "Pane #{pane_id} exited with status #{pane_dead_status}"'
set-hook -g pane-focus-in 'display "Focused pane #{pane_id}"'
set-hook -g pane-focus-out 'display "Unfocused pane #{pane_id}"'
set-hook -g pane-mode-changed 'display "Mode changed in pane #{pane_id}"'
set-hook -g pane-set-clipboard ''
set-hook -g pane-title-changed 'display "Pane title: #{pane_title}"'
Session Hooks
These hooks run for session events:
set-hook -g session-closed 'display "Session closed"'
set-hook -g session-created 'display "Session #{session_name} created"'
set-hook -g session-renamed 'display "Session renamed to #{session_name}"'
set-hook -g session-window-changed 'display "Window changed"'
Window Hooks
These hooks run for window events:
set-hook -g window-layout-changed 'display "Layout: #{window_layout}"'
set-hook -g window-linked 'display "Window linked"'
set-hook -g window-pane-changed 'display "Active pane changed"'
set-hook -g window-renamed 'display "Window renamed to #{window_name}"'
set-hook -g window-resized 'display "Window resized"'
set-hook -g window-unlinked 'display "Window unlinked"'
Hook Execution Context
Hooks execute with access to format variables relevant to the event:
# Access session variables
set-hook -g session-created 'display "Created: #{session_name}"'
# Access window variables
set-hook -g window-renamed 'display "Window #{window_index}: #{window_name}"'
# Access pane variables
set-hook -g pane-exited 'display "Pane #{pane_index} exit status: #{pane_dead_status}"'
Hook Examples
Automatic Logging
# Log pane output to file when created
set-hook -g after-split-window 'pipe-pane -o "cat >> ~/tmux-#S-#I-#P.log"'
Status Line Updates
# Update status line when window changes
set-hook -g after-select-window 'refresh-client -S'
# Update when pane focus changes
set-hook -g pane-focus-in 'refresh-client -S'
Theme Switching
# Automatically switch themes based on system theme
set-hook -g client-light-theme '
set -g status-style "bg=white,fg=black";
set -g pane-border-style "fg=colour240";
set -g pane-active-border-style "fg=colour33"
'
set-hook -g client-dark-theme '
set -g status-style "bg=black,fg=white";
set -g pane-border-style "fg=colour240";
set -g pane-active-border-style "fg=colour208"
'
Session Management
# Save session layout when window created
set-hook -g after-new-window 'run-shell "tmux-session-save #{session_name}"'
# Notify when session closes
set-hook -g session-closed 'run-shell "notify-send \"tmux\" \"Session closed\""'
Pane Lifecycle
# Set pane title when created
set-hook -g after-split-window 'select-pane -T "New pane"'
# Clean up when pane exits
set-hook -g pane-exited '
if -F "#{!=:#{pane_dead_status},0}"
"display \"Pane exited with error: #{pane_dead_status}\""
'
Window Monitoring
# Enable activity monitoring for new windows
set-hook -g after-new-window 'set -w monitor-activity on'
# Alert on activity
set-hook -g alert-activity '
display -d 3000 "Activity in window #{window_index}: #{window_name}"
'
Multiple Hook Commands
Hooks can run multiple commands using ; or by setting multiple array entries:
# Single hook with multiple commands
set-hook -g after-new-window '
set -w monitor-activity on;
set -w automatic-rename on
'
# Multiple hook entries (run in order)
set-hook -g after-new-window[0] 'set -w monitor-activity on'
set-hook -g after-new-window[1] 'set -w automatic-rename on'
Appending to Hooks
Use -a to add commands without replacing existing hooks:
# Set initial hook
set-hook -g after-new-window 'display "Window created"'
# Append additional command
set-hook -ag after-new-window 'set -w monitor-activity on'
# Both commands will run
Conditional Hooks
Use if-shell for conditional hook execution:
# Only notify if session has multiple windows
set-hook -g after-new-window '
if -F "#{>:#{session_windows},1}"
"display \"#{session_windows} windows in session\""
'
# Set options based on pane count
set-hook -g after-split-window '
if -F "#{>:#{window_panes},2}"
"set -w main-pane-width 120"
"set -w main-pane-width 80"
'
Hook Debugging
View configured hooks:
# Show all hooks
show-hooks
# Show specific hook
show-hooks after-new-window
# Show global hooks
show-hooks -g
Test hooks by running them manually:
# Run hook immediately with -R
set-hook -Rg after-new-window 'display "Test"'
Removing Hooks
Unset hooks to remove them:
# Remove specific hook
set-hook -ug after-new-window
# Remove hook for specific target
set-hook -u -t mysession after-new-window
# Remove all array entries
set-hook -ug after-new-window[0]
set-hook -ug after-new-window[1]
Hook Scope
Hooks can be set at different scopes:
# Global (affects all sessions)
set-hook -g after-new-window 'display "Global hook"'
# Session-specific
set-hook -t mysession after-new-window 'display "Session hook"'
# Window-specific (for window hooks)
set-hook -t mysession:1 window-renamed 'display "Window hook"'
More specific hooks override global ones.
Common Use Cases
set-hook -g session-created 'run-shell "tmux-resurrect save"'
set-hook -g session-closed 'run-shell "tmux-resurrect save"'
set-hook -g after-new-window 'run-shell "tmux-resurrect save"'
set-hook -g after-split-window 'select-pane -T "#{pane_current_command}"'
set-hook -g pane-focus-in 'select-pane -T "#{pane_current_command}"'
set-hook -g alert-activity 'run-shell "notify-send Activity #{window_name}"'
set-hook -g alert-bell 'run-shell "notify-send Bell #{window_name}"'
set-hook -g session-created '
new-window -n editor vim;
new-window -n shell;
select-window -t 1
'
set-hook -g after-split-window '
if -F "#{>:#{window_panes},3}"
"select-layout tiled"
"select-layout main-vertical"
'
Hook Best Practices
Keep hooks simple Hooks should execute quickly. For complex operations, call external scripts with run-shell.
Use format variables Leverage format variables to access context: #{session_name}, #{window_index}, etc.
Test thoroughly Hooks run automatically and can cause issues if misconfigured. Test with -R flag before relying on them.
Document your hooks Add comments explaining what each hook does and why it’s needed.
Hooks that fail or produce errors can disrupt tmux operation. Always test hooks before deploying them in production configurations.