Configuration
wtmux reads ~/.wtmux.conf (or ~/.tmux.conf as fallback). It supports a subset of tmux configuration syntax.
Note: After editing the config, run
wtmux reload-configorsource-filefrom the command prompt to re-read it without restarting the server.
See the Default Bindings reference for every built-in prefix, root, mouse, custom-table, and copy-mode binding and the exact override precedence.
Declarative DSC configuration
wtmux also ships a DSC v3 command resource for declarative global option management. The resource type is Shmuelie.WTmux/Options; it invokes wtmux dsc get, wtmux dsc test, and wtmux dsc set with JSON over standard input, so the same option names and values accepted by wtmux set-option -g are used in WinGet Configuration or DSC v3.
Example configuration.dsc.yaml:
$schema: https://aka.ms/configuration-dsc-schema/0.2
properties:
resources:
- resource: Shmuelie.WTmux/Options
id: wtmux-options
directives:
description: Configure wtmux global options
settings:
options:
prefix: C-a
mouse: 'on'
status-position: bottom
history-limit: 50000
The DSC resource talks to the per-user wtmux server and starts it if needed. test is idempotent: it reports _inDesiredState: true when the running server already has the desired option values and false when applying set would change them.
Example
# Change prefix key to Ctrl+A
set -g prefix C-a
# Default shell with arguments
set -g default-shell pwsh
set -g default-shell-arg -NoLogo
# Window numbering starts at 1
set -g base-index 1
# Add a command alias
set -g command-alias sp=split-window -h
# Enable mouse support
set -g mouse on
# Terminal settings
set -g default-terminal "screen-256color"
set -g history-limit 50000
set -g set-titles on
set -g set-titles-string '#S:#I:#W'
set -g clock-mode-style 24
set -g clock-mode-colour green
set -g automatic-rename on
set -g destroy-unattached off
set -g display-time 4000
# Hyperlinks (OSC 8)
set -g hyperlink-schemes http,https
set -g hyperlink-parameters id
# Activity, bell, and silence monitoring
set -g monitor-activity on
set -g monitor-bell on
set -g monitor-silence 60
set -g activity-action other
set -g bell-action any
set -g silence-action other
set -g visual-activity on
set -g visual-bell both
set -g visual-silence on
# Environment for new panes
set-environment -g WT_SESSION_MODE dev
set-environment -g -u NO_COLOR
# Status bar customization
set -g status-position bottom
set -g status-interval 5
set -g status-left '#{prefix_highlight} [#S] '
set -g status-right '%a %Y-%m-%d %H:%M'
set -g status-style fg=white,bg=black
set -g window-status-current-format ' #I:#W#F '
set -g window-status-format ' #I:#W#F '
# Custom key bindings
bind | split-window -h # Vertical split with |
bind - split-window # Horizontal split with -
bind h select-pane -L # Vim-style pane navigation
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind H resize-pane -L 5 # Vim-style pane resize (5 cells)
bind J resize-pane -D 5
bind K resize-pane -U 5
bind L resize-pane -R 5
unbind % # Remove default binding
# Include another config file
source-file ~/.wtmux.local.conf
# Run a PowerShell script during config loading
run 'Write-Output "set -g status-right $(Get-Date -Format HH:mm)"'
# Conditionally apply config based on a shell command's exit status
if-shell 'if (Get-Command git -ErrorAction SilentlyContinue) { exit 0 } else { exit 1 }' 'set -g status-left " git "'
Terminal title
Interactive create/attach commands set the friendly host title wtmux before connecting to the server. set-titles controls dynamic titles and is off by default: while it is off, the title stays wtmux, not an executable or package path. Turning it off at runtime returns to wtmux.
set -g set-titles-string <format> controls the title text. The default is #S:#I:#W (session name, window index, and window name). The format uses the same variables and time escapes as the status bar, including #P/#{pane_index}, #T/#{pane_title}, #H/#{host}, and #{host_short}. Runtime changes through wtmux set-option -g set-titles ... or wtmux set-option -g set-titles-string ... repaint attached clients and update the title immediately.
With set -g set-titles on, the first applicable screen update replaces the bootstrap title with the expanded format. All title text is sanitized. Each interactive client captures the console title before its bootstrap and restores that captured value once on detach, disconnect, or startup failure. A known empty title is restored as empty; an unavailable title is not guessed. Ctrl+C during startup restores the title before exiting; while attached, Ctrl+C continues to go to the pane, and cleanup restores the title when the client exits.
Restoration is limited to what the host exposes through GetConsoleTitle. If Windows Terminal or another host has already replaced the shell title with a process-derived title, this API cannot recover the earlier tab title. GetConsoleOriginalTitle is not a saved pre-wtmux shell-title snapshot. wtmux does not schedule later title writes that could overwrite the shell's next prompt title.
One-shot commands (including completion, DSC, and standalone menu/popup requests), help/version, invalid invocations, server-only startup, and commands with redirected input or output do not set a bootstrap title.
Terminal colors
Pane palette and default-color overrides are isolated from the host theme and from wtmux's status/border colors. Terminal colors describes the supported OSC controls, accepted specifications, and fallback table.
# Wait up to 250 milliseconds for unanimous host color replies (the default).
set -g color-query-timeout 250
The accepted range is 0-5000 milliseconds. Zero answers unmodified colors from
the canonical xterm fallback without querying hosts. At runtime, use
wtmux set-option -t work color-query-timeout 500 for a session override,
or wtmux set-option -t work -u color-query-timeout to restore global inheritance.
For a window shared by multiple sessions, each query batch uses the minimum
effective timeout across every owning session, including owners without attached
clients. Any owner's zero disables host queries for that batch. Registration
order does not matter; later option changes apply to new batches. Clients across
all owners still participate.
Mouse support
set -g mouse on enables mouse support (it is disabled by default). When enabled:
- Scroll wheel scrolls the active pane's scrollback. Scrolling up automatically enters copy mode so you can browse history; scrolling down returns toward the live view. When the active pane is running a full-screen application such as
lessthat requested application cursor keys, entered the alternate screen, or hid the cursor for full-screen input, but did not request mouse tracking, wheel input is translated to that application's Up/Down cursor keys instead. - Left-click selects the pane under the pointer.
- Right-click pastes the Windows clipboard into the pane under the pointer, falling back to the most recent paste buffer when the clipboard is empty or unavailable. The clipboard text is requested from the attached client that received the click and looked up with a bounded 2-second timeout, so the pane never blocks waiting for it; if neither the clipboard nor a paste buffer has text, wtmux shows a status message and leaves the pane's input unchanged instead of pasting anything.
- Left-button drag over a pane enters copy mode, selects text from the press cell to the current cell, and releasing copies the selection to the paste buffer and clipboard.
- Drag a pane border, or a cell immediately beside it, to resize the split.
- Mouse events are passed through to full-screen applications that request mouse tracking (for example editors), so their own mouse handling keeps working.
Pasting multi-line external clipboard text asks for confirmation before it reaches the pane, since wtmux synthesizes the paste directly into the pane's ConPTY and would otherwise bypass Windows Terminal's own native multi-line-paste warning — the safeguard against a hidden trailing command silently auto-running after what looked like a single-line copy. The prompt shows only how many lines are pending, never the clipboard text itself. Answering n, letting the prompt time out after 30 seconds, detaching, switching sessions, or closing the target pane before answering all leave the pane's input unchanged; none of them fall back to the paste buffer, since you were specifically asked about this content. Single-line clipboard text pastes immediately without a prompt, as does any paste (single- or multi-line) once the target pane requests bracketed-paste mode, since that application can tell pasted text apart from typed text itself.
The Windows clipboard lookup itself is a client-side capability, independent of the host terminal, so it is on by default; set WTMUX_CLIPBOARD_READ=0 (or false/no/off) before creating or attaching a client to opt that client out, in which case its right-clicks always fall back to the paste buffer.
With mouse support off, the scroll wheel is handled by your host terminal (for example, Windows Terminal scrolls its own window).
Mouse-aware applications such as Copilot CLI may own the selection gesture and
request a clipboard write on drag release. With the default clipboard policy,
that application-owned selection does not copy, even though wtmux's own
drag-selection still does. To explicitly allow eligible pane applications to
copy while retaining set-clipboard external, add:
set -g allow-application-clipboard on
This global option defaults to off. For an existing server, use
wtmux set-option -g allow-application-clipboard on; no reattach is needed.
Set it to off to revoke this opt-in. set-clipboard off always blocks all
clipboard writes, while set-clipboard on already authorizes application
writes and does not require the new option. Enabling the opt-in trusts eligible
active-pane applications to replace or clear the Windows clipboard, not just
copies associated with a mouse selection. It does not allow clipboard readback.
To keep application clipboard writes blocked, hold Shift to make a Windows Terminal selection instead. Shift+double-click followed by Shift+right-click copies a word through the host terminal without changing wtmux's policy. Remember that an ordinary wtmux-owned drag copies on release; its following right-click pastes rather than performing another copy.
Session cleanup
set -g destroy-unattached on destroys a session when its last attached client detaches, switches away, or disconnects because the terminal tab/process exits. It is disabled by default (off), so unattached sessions persist as before. The option is runtime-settable globally with wtmux set-option -g destroy-unattached on|off or per session with wtmux set-option [-t target] destroy-unattached on|off.
Detached sessions created before any client attaches are not destroyed immediately; cleanup only happens after an attached-client count transitions from at least one to zero. This avoids racing new-session -d creation with a later attach.
Hyperlinks
wtmux models OSC 8 hyperlinks as bounded per-cell metadata instead of forwarding
the raw escape sequence; see Hyperlinks (OSC 8) for
the full protocol and rendering behavior. hyperlink-schemes (default
http,https) and hyperlink-parameters (default id) are global-only options —
session-level runtime attempts are rejected rather than stored and ignored. See
the reference for accepted values.
A runtime wtmux set-option -g hyperlink-schemes ... or
wtmux set-option -g hyperlink-parameters ... change takes effect immediately
for both the server and every attached client, without discarding previously
stored link metadata.
Mouse bindings
Mouse actions are bindable with bind -n <mouse-key> <command>, using tmux-style named mouse keys. The event name combines an action, an optional button number (1 = left, 2 = middle, 3 = right), and a location (Pane or Status):
# Rebind the wheel, left-click, and right-click (built-in defaults under `mouse on`)
bind -n WheelUpPane copy-mode
bind -n MouseDown1Pane select-pane
bind -n MouseDown3Pane paste-buffer
# Middle-click a pane to open a new window
bind -n MouseDown2Pane new-window
# Remove a default mouse binding
unbind -n WheelUpPane
Recognized actions are WheelUp, WheelDown, MouseDown<n>, MouseUp<n>, MouseDrag<n>, and MouseDragEnd<n>. When mouse on is set, WheelUpPane/WheelDownPane (scrollback), MouseDown1Pane (select pane), and MouseDown3Pane (clipboard paste, falling back to the paste buffer) have built-in defaults that a bind/unbind -n overrides. An explicit wheel binding or unbind also takes precedence over alternate-screen wheel-to-arrow translation.
Root key bindings
bind -n <key> <command> also binds a keyboard key to fire without the prefix (tmux's root table), alongside the normal prefix bindings created by bind <key> <command>. -n is an alias for -T root; ordinary bind commands target the prefix table:
bind -n C-o new-window # Ctrl+O opens a new window without the prefix
bind -T root C-p previous-window
Root key bindings match raw input bytes before the prefix, so bind control or special keys (e.g. C-o) rather than plain letters — a letter binding would also fire when that byte appears inside an escape sequence (such as arrow keys) or pasted text.
Custom key tables
Use bind -T <table> and unbind -T <table> to define named key tables. A binding can enter one with switch-client -T <table>:
bind n switch-client -T navigation
bind -T navigation h select-pane -L
bind -T navigation j select-pane -D
bind -T navigation k select-pane -U
bind -T navigation l select-pane -R
unbind -T navigation q
After prefix n, the next key is looked up in navigation. Custom tables are one-shot: the next key is consumed and the client returns to root whether the key matches or not. A matched binding runs through the normal runtime command path; it may use another switch-client -T to continue a longer sequence. Switching to an undefined or invalid table reports an error.
For this initial key-table slice, switch-client -T must be the only command on its command line. Combining it with ; and server commands is rejected; ordinary all-server command sequences continue to run server-side with their existing ordering and stop-on-error behavior.
This is partial advanced-binding support. Repeatable bind -r behavior, binding notes (bind -N), list-keys, and send-prefix are not implemented.
Configuration options
See the Configuration Options reference for every supported option, accepted values, defaults, and runtime scope.
Conditional Configuration
wtmux evaluates run-shell and if-shell directives while loading the config file.
run-shell
run-shell 'shell-command'
run 'shell-command' # short alias
Runs shell-command (via pwsh/powershell, falling back to cmd) and feeds
each line of its standard output back to the parser as a wtmux command. Only
set / setw, bind, and unbind commands are recognized in the output.
if-shell
if-shell [-b] shell-command then-command [else-command]
if [-b] shell-command then-command [else-command] # short alias
Runs shell-command. If it exits with status 0, then-command is executed as
a wtmux command; otherwise the optional else-command runs. then-command and
else-command are ordinary config commands (usually quoted) and may be any
supported directive, including a nested if-shell or source-file.
# Apply a different prefix when running under an SSH session
if-shell 'if ($env:SSH_CONNECTION) { exit 0 } else { exit 1 }' \
'set -g prefix C-a' 'set -g prefix C-b'
Supported semantics and notes:
- The exit status of the shell command determines the branch (
0= success →then-command; non-zero, or a command that fails to launch →else-command). -b(run the command in the background) is accepted for tmux compatibility, but the command is always evaluated synchronously at config load time.- Commands are run with a 5-second timeout; a command that times out or cannot be launched is treated as a failure.
Environment
Use set-environment to configure environment variables for panes created after
the server loads the config:
set-environment [-g] NAME VALUE
set-environment [-g] -u NAME
show-environment [-g]
Config-time environment changes are global. Runtime set-environment without
-g applies to the current session; with -g, it updates the global
environment. Configured values override inherited variables, and -u removes a
variable from the child process environment. wtmux still sets WTMUX and
WTMUX_PANE for each pane.
Format Variables
Status formats (status-left, status-right, window-status-format, window-status-current-format) support tmux-style # variables, #{...} expressions, % time escapes, and inline #[...] style directives.
| Variable | Description |
|---|---|
#S / #{session_name} |
Session name |
#I / #{window_index} |
Window index |
#W / #{window_name} |
Window name |
#F / #{window_flags} |
Window flags (* current, - last, # activity, ! bell, ~ silence, Z zoomed) |
#P / #{pane_index} |
Pane index |
#H / #{host} / #{hostname} |
Hostname |
#{host_short} |
Hostname before the first dot |
#T / #{pane_title} |
Pane title |
#{pane_pid} |
Pane process ID |
#{pane_current_path} |
Pane working directory, initialized from the launch directory and updated when the shell emits OSC 7 (file://...) or OSC 9;9 cwd reports |
#{session_windows} |
Number of windows in the session |
#{window_activity} |
Last window output time as a Unix timestamp |
#{client_prefix} |
1 while the prefix key is active; otherwise 0 |
#{synchronize_panes} / #{pane_synchronized} |
1 when synchronize-panes is enabled for the active window; otherwise 0 |
#{@name} |
Value of the @name user option, or empty when unset (see User options) |
#{prefix_highlight} |
Prefix key indicator supplied by the built-in prefix-highlight plugin |
Format Expressions
| Expression | Description |
|---|---|
#{?condition,yes,no} |
Conditional text. condition may be a variable or nested expression and is true when it expands to a non-empty value other than 0, false, no, or off. |
#{==:left,right} |
Expands to 1 when the expanded values are equal; otherwise 0. |
#{!=:left,right} |
Expands to 1 when the expanded values differ; otherwise 0. |
#{m:pattern,string} |
Expands to 1 when string matches pattern. * and ? use glob matching; patterns without wildcards use substring matching. |
#{s/old/new/:value} |
Replaces old with new in the expanded value. The delimiter after s can be any character. |
#{=<N>:value} |
Trims the expanded value to N visible columns. |
#{p<N>:value} |
Pads the expanded value with spaces to at least N visible columns. |
#{t:value} |
Formats an expanded timestamp value such as #{t:window_activity}. Unix seconds and parseable date/time strings are accepted. |
#{W:body} |
Expands body once for each window in the current session, with window variables (#I, #W, #F, #{window_activity}) scoped to that window. |
#{P:body} |
Expands body once for each pane in the current window, with pane variables (#P, #T, #{pane_pid}, #{pane_current_path}) scoped to that pane. |
Use \, for a literal comma inside conditional or operator arguments. Nested #{...} expressions are supported inside arguments, branches, and loop bodies. Session loop expressions (#{S:...}) are reserved but not populated by the status renderer yet.
Inline Styles
Use #[...] inside a status format to change the style for following text:
set -g status-left '#[fg=green,bold]#S#[default] '
set -g status-right '#[fg=colour220,bg=black] %H:%M #[default]'
Supported style entries are fg=<color>, bg=<color>, bold, dim, reverse, underline, default, and none. #[default] and #[none] reset back to the base status-style/status-fg/status-bg. Inline style escape sequences do not count toward status-line width or truncation.
Time Formats
| Format | Description | Example |
|---|---|---|
%H |
Hour (24h) | 14 |
%I |
Hour (12h) | 02 |
%M |
Minute | 35 |
%S |
Second | 09 |
%R |
HH:MM | 14:35 |
%T |
HH:MM:SS | 14:35:09 |
%p |
AM/PM | PM |
%P |
am/pm | pm |
%a |
Day abbreviation | Mon |
%A |
Day full name | Monday |
%d |
Day of month | 07 |
%e |
Day (space-padded) | 7 |
%b / %h |
Month abbreviation | Jan |
%B |
Month full name | January |
%m |
Month number | 01 |
%Y |
Year | 2026 |
%j |
Day of year | 042 |
%k |
Hour (space-padded 24h) | 14 |
%l |
Hour (space-padded 12h) | 2 |
Colors
Named colors: red, green, blue, yellow, cyan, magenta, white, black, default
256-color palette: colour0 through colour255 (or color0 through color255). Numeric palette indexes are also accepted.