Repository navigation
Events
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.
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 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
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.
| 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 |
The tmux commands below use configuration file syntax.
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}"'
}
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'
}
}
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
}
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'
}
}
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
}
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
|