Skip to content
Nicholas Marriott edited this page Sep 3, 2026 · 1 revision

Using events, hooks and monitors

This document explains how to use events, hooks and monitors:

  • events allow tmux to report that something has happened;
  • hooks run tmux commands in response;
  • and monitors create events when a format changes.

This document covers tmux 3.8 and later: many of these features are not available on older versions.

Events and monitors are closely tied to formats, which are documented here.

Hooks

A hook is a tmux command or command sequence which is run when an event happens. Each hook is a named option: there are builtin hooks (such as pane-exited) and custom hooks ("user hooks") may be created by starting the name with an @ (such as @myhook).

Hooks are set using the set-hook command:

$ tmux set-hook -g window-renamed \
    'display-message "#{hook_old_name} is now #{hook_new_name}"'
$ tmux set-hook -g after-split-window \
    'select-layout tiled ; display-message "new pane: #{pane_id}"'

Builtin hooks (but not user hooks) are array options, so multiple commands may be added to the same hook by using different keys:

$ tmux set-hook -g 'pane-exited[message]' \
    'display-message "pane #{hook_pane} exited"'
$ tmux set-hook -g 'pane-exited[update]' \
    'set-option -g -F @lastexit "#{hook_pane}"'

Like options, hooks have a scope which controls where they apply and how long they remain set. For a user hook, the scope is set with a flag to set-hook:

Flag Scope
-g Global session
None Session
-g -w Global window
-w Window
-p Pane

When a user hook is executed, tmux looks in the target session first, followed by the target pane and then the target window, and runs the first hook it finds.

Each builtin hook has a default scope which is used if no flag is given; -g uses the global form of this scope. Some window hooks can also be set on a pane with -p; for example, pane-exited can be set for all panes in all windows:

$ tmux set-hook -g pane-exited \
    'display-message "pane #{hook_pane} exited"'

Or for all panes in one window:

$ tmux set-hook -w -t @1 pane-exited \
    'display-message "pane #{hook_pane} exited"'

Or for a single pane:

$ tmux set-hook -p -t %7 pane-exited \
    'display-message "pane #{hook_pane} exited"'

See this table for the default scope and whether pane scope is available for each hook.

Hooks can be removed using set-hook -u:

$ tmux set-hook -u -g 'pane-exited[message]'
$ tmux set-hook -u -g pane-exited

Or displayed with show-hooks. With no hook name, the scope flags select which hooks to show, for example:

$ tmux show-hooks -g
$ tmux show-hooks -g -w
$ tmux show-hooks -p -t %7

When a builtin hook name is given, tmux already knows its default scope. For example:

$ tmux show-hooks -g pane-exited

Within a hook, the hook format variable is the hook name and any keys in the event payload (see below) are available prefixed with hook_. For example, the window-renamed event includes window, old_name and new_name:

$ tmux set-hook -g window-renamed \
    'display-message "#{hook_window}: #{hook_old_name} -> #{hook_new_name}"'

set-hook -R executes a hook immediately.

Events

Events are fired by tmux when something happens. Each hook has a corresponding event: when the event happens, the hook is executed. Like user hooks, user events have names starting with @. The builtin events and hooks are listed in this table.

User events may be fired by set-hook -E or a monitor (see below). For example:

$ tmux set-hook -g @buildfinished \
    'display-message "build finished in #{session_name}"'
$ tmux set-hook -E @buildfinished

Or to fire an event for a specific target:

$ tmux set-option -g @buildresult finished
$ tmux set-hook -E -t work:2.1 '@build#{@buildresult}'

The wait-for -E command waits for an event. After the event is fired, the command finishes:

$ tmux wait-for -E pane-exited

Each event has a payload consisting of keys and values. -v prints the payload when an event arrives:

$ tmux wait-for -E -v window-renamed
event=window-renamed
new_name=editor
old_name=shell
window=@3

-F allows the event to be filtered by its payload, for example to wait for a single pane:

$ tmux wait-for -E -F '#{==:#{pane},%7}' pane-exited

-l lists the clients waiting for an event, for example:

$ tmux wait-for -E -l pane-exited
client-12345

Monitors

A monitor expands a format once a second and fires a user event if the result has changed. The first time the format is expanded the value is recorded but the event is not fired - the event will fire only when there are two values to compare.

Monitors are added with set-hook -B. The argument looks like this:

@name:what:format

name is the name of the event fired (and the hook executed, if it exists). It must begin with @. what chooses what the format checks:

Value What is checked
Empty The target session
%3 Pane %3 in the target session
%* Every pane in the target session
@2 Window @2 in the target session
@* Every window in the target session

This example adds a monitor and a hook called @sessionnamechanged which fires each time the work session name is changed:

$ tmux set-hook -B '@sessionnamechanged::#{session_name}' -t work \
    'display-message "#{hook_last} -> #{hook_value}"'

A monitor may be set without a hook, either for use with wait-for -E or because the hook is set separately. For example, to monitor every pane in the work session:

$ tmux set-hook -t work @commandchanged \
    'display-message "#{hook_pane}: #{hook_last} -> #{hook_value}"'
$ tmux set-hook -B '@commandchanged:%*:#{pane_current_command}' -t work

Like hooks, monitors have a scope. Monitors run only the hook on the same session, window or pane. A monitor set with set-hook -B '@name::format' -w -t @1 will only run hooks set with set-hook -w -t @1.

When a monitor fires, value is the new value and last the previous one (in hooks these are hook_value and hook_last):

$ tmux set-hook -B '@size:%*:#{pane_width}x#{pane_height}' -t work \
    'display-message "#{hook_pane}: #{hook_last} -> #{hook_value}"'

If a monitor is set with -T, it fires only if the new value is true (not empty and not zero):

$ tmux set-hook -B '@copymode:%*:#{pane_in_mode}' -T -t work \
    'display-message "#{hook_pane} entered a mode"'

show-hooks -B shows monitors:

$ tmux show-hooks -B -t work
@size:%*:#{pane_width}x#{pane_height}

-F can be used to show additional details:

$ tmux show-hooks -B -t work -F \
    '#{option_name} target=#{hook_monitor_target} format=#{hook_monitor_format} fired=#{hook_fire_count}'

-u removes a monitor:

$ tmux set-hook -B @size -u -t work

Removing a monitor does not remove any hooks, even if one was added together with the monitor.

Which should I use?

Task What
Run a command on a builtin action An ordinary hook such as pane-exited or after-split-window
Wait for some state to change A monitor hook (set-hook -B)
A signal between scripts A user event
A script waiting for something to happen wait-for -E

Examples

The tmux commands below use configuration file syntax.

Mark and jump to the most recently failed pane

This puts a ! in the status line beside any windows with a pane that exited with failure and adds an F key binding to jump to the most recent (if it is still open).

set -g remain-on-exit failed
set -g window-status-format '#I:#W#{P:#{?pane_dead,#[fg=red]!,}}'
set -g window-status-current-format '#I:#W*#{P:#{?pane_dead,#[fg=red]!,}}'

set-hook -g pane-died {
    set-option -F @failedpane '#{hook_pane}'
}
bind F {
    run-shell -C 'select-window -t "#{@failedpane}"; select-pane -t "#{@failedpane}"'
}

Display a message when a long command finishes

This displays a message if a command in a pane finishes after more than 60 seconds. This needs the shell to emit the OSC 133 command sequences.

set-hook -g pane-command-finished {
    if-shell -F '#{e|>=|:#{hook_command_duration},60}' {
        display-message 'Command in #{hook_pane} finished after #{hook_command_duration}s'
    }
}

Change layouts when a window becomes narrow or wide

This monitors each window in the work session and selects the main-horizontal layout when one becomes narrower than 100 columns and the tiled layout when it becomes wider.

set-hook -B '@narrow:@*:#{e|<|:#{window_width},100}' -T -t work {
    select-layout -t '#{hook_window}' main-horizontal
}
set-hook -B '@wide:@*:#{e|>=|:#{window_width},100}' -T -t work {
    select-layout -t '#{hook_window}' tiled
}

Unset synchronize-panes when leaving a window

This unsets synchronize-panes when the window is no longer current, so it returns to the global value.

set-hook -g session-window-changed {
    if-shell -F '#{hook_old_window}' {
        run-shell -C 'set-option -u -w -t "#{hook_old_window}" synchronize-panes'
    }
}

Show a spinner while a long command is running

This shows a spinner in the pane status line if a command has been running for more than three seconds. This needs the shell to emit the OSC 133 command sequences.

set -g pane-border-status top
set -g -F -o -q @oldpaneborderformat '#{pane-border-format}'
set -g pane-border-format \
    '#{?#{&&:#{!:#{alternate_on}},#{pane_command_running},#{e|>:#{pane_command_duration},3}},#{A/2:|,/,-,\} ,}#{E:@oldpaneborderformat}'

set-hook -B '@spinner::#{S:#{W:#{P:#{&&:#{!:#{alternate_on}},#{pane_command_running},#{e|>:#{pane_command_duration},3}}}}}' -g {
    refresh-client -S
}

Builtin events and hooks

Each name below is both:

  • an event fired by tmux;
  • a builtin hook.

The default scope is used when set-hook has no -g, -w or -p flag. Hooks with a ✓ in the pane column may be used with -p.

Every payload includes an event key. A payload key marked with * means that it is included only when available. Target fields are session, window, window_index and pane.

Name Default scope Pane When Payload
alert-activity Session A monitored window has activity session, window, window_index
alert-bell Session A monitored window receives a bell session, window, window_index
alert-silence Session A monitored window has been silent for its configured interval session, window, window_index
client-active Session A client becomes the latest active client of its session client, target fields*
client-attached Session A client attaches client, target fields*
client-created Session A client is created client, target fields*
client-closed Session A client closes client, target fields*
client-detached Session A client detaches client, target fields*
client-focus-in Session Focus enters a client client, target fields*
client-focus-out Session Focus leaves a client client, target fields*
client-light-theme Session A client changes to a light theme client, target fields*
client-dark-theme Session A client changes to a dark theme client, target fields*
client-resized Session A client changes size client, target fields*, old_width, old_height, width, height
client-session-changed Session A client changes its attached session client, target fields*, old_session*, new_session*
command-error Session A tmux command fails, except for a command run from a hook arguments, argument_N, flag_X
marked-pane-changed Session The marked pane is set, changed or cleared pane, window, marked, old_pane*, new_pane*
pane-activity Window ✓ A pane produces output pane, window
pane-bell Window ✓ A pane receives a bell pane, window
pane-command-finished Window ✓ An OSC 133 shell command finishes session*, window, window_index*, pane, command_status*, command_start_time*, command_end_time, command_duration*
pane-command-started Window ✓ An OSC 133 shell command starts session*, window, window_index*, pane, command_start_time, command_duration
pane-created Window ✓ A pane is created or respawned session, window, window_index, pane, pane_command*, pane_current_path*, created_empty, created_respawn
pane-died Window ✓ A pane process exits and remain-on-exit keeps the pane pane, window, exit_success, exit_status*, exit_signal*
pane-exited Window ✓ A pane process exits and the pane is removed pane, window, exit_success, exit_status*, exit_signal*
pane-focus-in Window ✓ Focus enters a pane and focus-events is on pane, window
pane-focus-out Window ✓ Focus leaves a pane and focus-events is on pane, window
pane-mode-changed Window ✓ The top pane mode changes pane, window, mode_entered, previous_mode*, current_mode*
pane-mode-entered Window ✓ A pane enters a mode pane, window, mode_entered, previous_mode*, current_mode*
pane-mode-exited Window ✓ A pane exits a mode pane, window, mode_entered, previous_mode*, current_mode*
pane-moved Window ✓ A pane moves to another window pane, window, window_index*, old_window, new_window, old_window_index*, new_window_index*
pane-prompt-opened Window ✓ A prompt opens in a pane pane, window, prompt_type
pane-prompt-closed Window ✓ A prompt closes in a pane pane, window, prompt_type
pane-resized Window ✓ A pane changes size pane, window, old_width, old_height, width, height
pane-set-clipboard Window ✓ A pane sets the terminal clipboard pane, window
pane-shell-prompt Window ✓ An OSC 133 shell prompt starts pane, window
pane-title-changed Window ✓ A pane title changes pane, window, new_title
session-added-to-group Session A session is added to a group session, group, group_size
session-closed Session A session closes session
session-created Session A session is created session
session-removed-from-group Session A session is removed from a group session, group, group_size
session-renamed Session A session is renamed session, old_name, new_name
session-window-changed Session A session changes current window session, window, window_index, old_window*, old_window_index*, new_window, new_window_index
window-closed Window A window closes window
window-created Window A window is created window
window-layout-changed Window A window layout changes window
window-linked Session A window is linked into a session session, window, window_index
window-pane-changed Window A window changes active pane window, pane, old_pane*, new_pane
window-renamed Window A window is renamed window, old_name, new_name
window-resized Window A window changes size window, old_width, old_height, width, height
window-unlinked Session A window is unlinked from a session session, window, window_index
window-unzoomed Window A window is unzoomed window
window-zoomed Window A window is zoomed window
after-<command> Session A command with an after hook succeeds (not every command has one), except for a command run from a hook arguments, argument_N, flag_X

Clone this wiki locally