Configuration
bmux is configured via a bmux.toml file. If no config file exists, bmux uses sensible defaults for all options.
Config File Location
bmux resolves bmux.toml from the configured config directory candidate chain. Use the path/env override table below to pin exact locations.
Path & Env Overrides
bmux supports environment-variable overrides for config/runtime/data directories and recording storage.
| Variable | Scope | Behavior |
| BMUX_CONFIG | config | Merges an additional config file after discovered config (lower precedence than –config). |
| BMUX_CONFIG_DIR | config | Overrides the config directory root and disables fallback candidate chaining. |
| BMUX_RUNTIME_DIR | runtime | Overrides the runtime root used for sockets and temp runtime artifacts. |
| BMUX_RUNTIME_NAME | runtime | Selects the runtime instance name; non-default values use runtime subdirectories. |
| BMUX_DATA_DIR | data | Overrides the persistent data directory (plugins and runtime identity files). |
| BMUX_STATE_DIR | state | Overrides the persistent state directory (recordings, traces, and runtime layout state); when BMUX_LOG_DIR is unset, logs default to $BMUX_STATE_DIR/logs. |
| BMUX_LOG_DIR | logs | Overrides the log directory used by bmux file logging. |
| BMUX_RECORDINGS_DIR | recordings | Overrides recording storage root for recording CLI/runtime resolution. |
| BMUX_SLOT_NAME | slot | Forces the active bmux slot. Overrides argv[0] parsing. When unset, the binary’s basename (bmux- |
| BMUX_SLOTS_MANIFEST | slot | Path to the slot manifest (slots.toml). - means read from stdin. Defaults to <config_dir>/slots.toml. |
| BMUX_SLOTS_ROOT | slot | Root directory under which per-slot default dirs are materialized. Defaults to the platform data dir. |
| BMUX_SLOTS_BIN_DIR | slot | Directory containing the bmux- |
| BMUX_NO_BASE_CONFIG | config | When set to a truthy value, disables merging the shared ~/.config/bmux/base.toml layer for this invocation. |
| BMUX_MANIFEST_READ_ONLY_PREFIXES | slot | Colon-separated path prefixes that, when a manifest file lives under one of them, make write-side helpers refuse to modify the file. |
[general]
Core session defaults: shell, scrollback depth, and server connection settings
| Option | Type | Default | Description |
| default_mode | string (normal, insert, visual, command) | NORMAL | Default interaction mode when starting bmux |
| mouse_support | bool | true | Enable mouse support for clicking to focus panes, scrolling through output, and dragging to resize pane borders |
| default_shell | string (optional) | — | Default shell to launch in new panes. When unset, uses the SHELL environment variable or falls back to /bin/sh. |
| scrollback_limit | integer | 10000 | Maximum number of scrollback lines retained per pane. Must be at least 1. |
| server_timeout | integer | 5000 | Server socket timeout in milliseconds. Must be at least 1. |
[appearance]
Visual styling: pane borders, status bar placement, and window titles
| Option | Type | Default | Description |
| status_position | string (TOP, BOTTOM, OFF) | BOTTOM | Where to render the status bar. TOP places it above panes, BOTTOM below panes, and OFF hides it entirely. |
| pane_border_style | string (SINGLE, DOUBLE, ROUNDED, THICK, NONE) | SINGLE | Drawing style for pane borders. NONE hides borders entirely, giving panes the full terminal width. |
| show_pane_titles | bool | false | Display a title label in each pane’s border showing the running process name |
| window_title_format | string | (empty) | Format string for the outer terminal’s title bar. Empty string leaves the title unset. |
[behavior]
Runtime behavior toggles for terminal protocol handling, layout persistence, and build compatibility
| Option | Type | Default | Description |
| aggressive_resize | bool | false | Immediately resize panes to the largest remaining client when a client disconnects, rather than keeping the previous dimensions |
| visual_activity | bool | false | Highlight panes in the status bar when they produce output while unfocused, so you can tell which panes have new activity |
| bell_action | string (NONE, ANY, CURRENT, OTHER) | ANY | How to handle terminal bell signals from panes. NONE ignores bells entirely. ANY notifies on bells from any pane. CURRENT only notifies from the focused pane. OTHER only notifies from unfocused panes. |
| automatic_rename | bool | false | Automatically rename windows based on the currently running command in the focused pane |
| exit_empty | bool | false | Exit bmux when no sessions remain |
| restore_last_layout | bool | true | Restore and persist the last local CLI runtime layout across sessions, so reattaching resumes where you left off |
| confirm_quit_destroy | bool | true | Prompt for confirmation before a destructive quit that clears persisted local runtime state |
| pane_term | string | bmux-256color | Terminal type exposed to pane processes via the TERM environment variable. Common values: bmux-256color, xterm-256color, screen-256color. |
| pane_shell_integration | bool | true | Enable per-shell runtime integration hooks that emit verbatim pane command and prompt metadata for resurrection. When disabled, bmux does not inject shell wrapper config/rc files and falls back to best-effort process inspection for command/cwd restore. |
| protocol_trace_enabled | bool | false | Enable protocol query/reply tracing in the runtime. Useful for debugging terminal protocol behavior with CSI/OSC/DCS sequences. |
| protocol_trace_capacity | integer | 200 | Maximum number of in-memory protocol trace events to retain. Must be at least 1. |
| terminfo_auto_install | string (ask, always, never) | never | What to do when the bmux terminfo entry is missing from the system. ask prompts before installing. always installs silently. never skips installation, which may degrade terminal rendering. |
| terminfo_prompt_cooldown_days | integer | 7 | Number of days to wait before prompting again after the user declines terminfo installation |
| stale_build_action | string (ignore, warn, error) | ignore | What to do when the running server was built from a different version than the current CLI binary. ignore skips stale-build checks. warn connects with a warning message. error refuses to connect until the server is restarted. |
| kitty_keyboard | bool | true | Enable the Kitty keyboard protocol for enhanced key reporting. When true, bmux negotiates enhanced keyboard mode with the outer terminal, allowing modified special keys like Ctrl+Enter to be correctly forwarded to pane programs. |
| pane_restore_method | string (snapshot, retain) | snapshot | How to restore pane content when hidden panes become visible again (e.g. after exiting zoom). SNAPSHOT re-fetches from the server for guaranteed accuracy. RETAIN keeps parsers in memory for instant restore. |
| mouse.enabled | bool | true | Master toggle for mouse handling in attach mode. |
| mouse.focus_on_click | bool | true | Focus pane when clicking inside it. |
| mouse.click_propagation | string (focus_only, forward_only, focus_and_forward) | focus_and_forward | How pane-area mouse clicks are routed between bmux and pane TUIs. |
| mouse.focus_on_hover | bool | false | Focus pane when hovering over it. |
| mouse.hover_delay_ms | integer | 175 | Hover dwell time before focus is applied. |
| mouse.scroll_scrollback | bool | true | Route wheel scrolling to focused pane scrollback. |
| mouse.wheel_propagation | string (auto, forward_only, scrollback_only, forward_and_scrollback) | auto | How wheel events are routed between pane TUIs and bmux scrollback. |
| mouse.scroll_lines_per_tick | integer | 3 | Number of scrollback lines per mouse wheel tick. |
| mouse.exit_scrollback_on_bottom | bool | true | Exit scrollback mode automatically when wheel scrolling reaches bottom. |
| mouse.alternate_screen_wheel | string (ignore, forward_only, scrollback_only) | ignore | How wheel events behave in alternate-screen panes that have not requested mouse tracking. |
| mouse.selection_release | string (select, copy, copy_and_exit) | select | What to do when a bmux-managed mouse selection drag is released. |
| mouse.resize_borders | bool | true | Resize panes by dragging shared pane borders. |
| mouse.resize_drag_throttle_ms | integer | 32 | Minimum interval in milliseconds between resize requests while dragging pane borders. Set to 0 to apply every drag event. Mouse release always applies the final position. |
| mouse.gesture_actions | table | (empty) | Optional mouse gesture overrides mapped to action names. Supported keys in the current core runtime are click_left, hover_focus, scroll_up, and scroll_down. Values use the same action naming format as keybindings, including built-in action names and plugin:<id>:<command>. |
| damage.max_rects | integer | 64 | Maximum damaged rectangles to track per surface before falling back to a full-surface repaint. |
| damage.max_area_percent | integer | 60 | Damaged cell-area percentage that triggers a full-surface repaint fallback. Must be 1 through 100. |
| damage.visualize | bool | false | Draw a colored debug overlay around regions repainted by attach damage tracking. |
| event_coalescing.max_events_per_frame | integer | 64 | Maximum ready server events to drain before rendering one attach frame. |
| images.enabled | bool | true | Master switch for Sixel, Kitty graphics, and iTerm2 inline image support. When false, image escape sequences are passed through to the host terminal without interception or registry tracking. |
| images.decode_mode | string (server, client, passthrough) | passthrough | How image decoding is distributed between server and client. PASSTHROUGH forwards raw protocol bytes with coordinate translation (fastest, requires same protocol support on the host terminal). SERVER decodes images to pixel buffers on the server side. CLIENT sends raw bytes for the client to decode and re-encode. |
| images.max_image_bytes | integer | 10485760 | Maximum image payload size in bytes per image. Images exceeding this limit are silently discarded to prevent memory exhaustion. |
| images.max_images_per_pane | integer | 100 | Maximum number of images kept in the registry per pane. When this limit is reached, the oldest images are evicted (FIFO). |
| compression.enabled | bool | true | Master switch for all compression. When false, image payloads are sent uncompressed and remote connections are not wrapped in streaming compression. |
| compression.images | string (none, auto, zstd, lz4) | auto | Compress image payloads (Sixel, Kitty graphics, iTerm2) before IPC transport. Typical reduction: 5-15x for sixel text, 3-20x for kitty raw pixels. Pre-compressed formats (e.g. kitty PNG) are automatically detected and skipped. auto selects zstd when available. |
| compression.remote | string (none, auto, zstd, lz4) | auto | Compress remote connections (TLS gateway, Iroh P2P) with streaming compression. Local Unix socket connections are never compressed. Both the client and the server gateway must use the same setting; a mismatch will cause the connection to fail. If SSH is already compressing the tunnel, set this to none to avoid double work. |
| compression.level | integer | 3 | Zstd compression level for image payloads (1-19, ignored for lz4). Level 1 is fastest (~500 MB/s), level 3 (default) balances speed and ratio, level 9+ gives diminishing returns. Remote streaming always uses level 1 internally for low latency regardless of this setting. |
[multi_client]
Settings for multiple clients attached to the same session
| Option | Type | Default | Description |
| allow_independent_views | bool | false | Allow clients to have independent views of the same session, with separate focused panes and scroll positions |
| default_follow_mode | bool | false | When true, new clients automatically track the leader client’s focused pane and scroll position. When false, clients start with an independent view. |
| max_clients_per_session | integer | 0 | Maximum number of clients that can attach to a single session. Set to 0 for unlimited. |
| sync_client_modes | bool | false | When true, switching interaction modes (e.g. Normal to Insert) on one client applies to all attached clients in the same session |
[keybindings]
Keyboard shortcuts organized by scope and interaction mode
| Option | Type | Default | Description |
| initial_mode | string | normal | Initial interaction mode id. Mode ids are matched case-insensitively. |
| modes | table | (see defaults below) | First-class modal keymap definitions keyed by mode id. |
| prefix | string | ctrl+a | Prefix key for runtime key chords (e.g. “ctrl+a”). All runtime bindings require pressing this key first. Legacy path only. |
| timeout_ms | integer (optional) | — | Exact timeout in milliseconds for multi-stroke chord resolution. Takes precedence over timeout_profile. Valid range: 50-5000. |
| timeout_profile | string (optional) | — | Named timeout profile for multi-stroke chord resolution. Built-in profiles: fast (200ms), traditional (400ms), slow (800ms). Ignored when timeout_ms is set. |
| timeout_profiles | table | (empty) | Override values for built-in timeout profiles or define custom ones. Keys are profile names, values are timeout in milliseconds. |
| runtime | table | (see defaults below) | Key bindings triggered after pressing the prefix key. Maps key chords to runtime action names. |
| global | table | (see defaults below) | Key bindings that trigger without the prefix key. Use sparingly to avoid conflicts with pane input. |
| scroll | table | (see defaults below) | Key bindings active in scrollback/copy mode. No prefix required unless the chord explicitly includes it. |
Default modes bindings
[keybindings.modes]
[insert]
label = "INSERT"
passthrough = true
[insert.bindings]
"ctrl+a escape" = "enter_mode normal"
[normal]
label = "NORMAL"
passthrough = false
[normal.bindings]
'"' = "plugin:bmux.windows:split-pane --direction horizontal"
"%" = "plugin:bmux.windows:split-pane --direction vertical"
"(" = "plugin:bmux.windows:prev-window"
")" = "plugin:bmux.windows:next-window"
"?" = "show_help"
"[" = "enter_scroll_mode"
"]" = "exit_scroll_mode"
"^" = "plugin:bmux.windows:last-window"
arrow_down = "plugin:bmux.windows:focus-pane-in-direction --direction down"
arrow_left = "plugin:bmux.windows:focus-pane-in-direction --direction left"
arrow_right = "plugin:bmux.windows:focus-pane-in-direction --direction right"
arrow_up = "plugin:bmux.windows:focus-pane-in-direction --direction up"
c = "plugin:bmux.windows:new-window"
"ctrl+e" = "scroll_down_line"
"ctrl+y" = "scroll_up_line"
d = "detach"
g = "scroll_top"
h = "plugin:bmux.windows:focus-pane-in-direction --direction left"
i = "enter_mode insert"
j = "plugin:bmux.windows:focus-pane-in-direction --direction down"
k = "plugin:bmux.windows:focus-pane-in-direction --direction up"
l = "plugin:bmux.windows:focus-pane-in-direction --direction right"
minus = "plugin:bmux.windows:resize-pane --direction decrease"
o = "plugin:bmux.windows:focus-pane-in-direction --direction next"
page_down = "scroll_down_page"
page_up = "scroll_up_page"
plus = "plugin:bmux.windows:resize-pane --direction increase"
q = "quit"
r = "plugin:bmux.windows:restart-pane"
"shift+arrow_down" = "plugin:bmux.windows:resize-pane --direction down"
"shift+arrow_left" = "plugin:bmux.windows:resize-pane --direction left"
"shift+arrow_right" = "plugin:bmux.windows:resize-pane --direction right"
"shift+arrow_up" = "plugin:bmux.windows:resize-pane --direction up"
"shift+c" = "plugin:bmux.sessions:new-session"
"shift+g" = "scroll_bottom"
"shift+h" = "plugin:bmux.windows:resize-pane --direction left"
"shift+j" = "plugin:bmux.windows:resize-pane --direction down"
"shift+k" = "plugin:bmux.windows:resize-pane --direction up"
"shift+l" = "plugin:bmux.windows:resize-pane --direction right"
v = "begin_selection"
x = "plugin:bmux.windows:close-active-pane"
z = "plugin:bmux.windows:zoom-pane"
Default runtime bindings
[keybindings.runtime]
'"' = "plugin:bmux.windows:split-pane --direction horizontal"
"%" = "plugin:bmux.windows:split-pane --direction vertical"
"(" = "plugin:bmux.windows:prev-window"
")" = "plugin:bmux.windows:next-window"
"?" = "show_help"
"[" = "enter_scroll_mode"
"]" = "exit_scroll_mode"
"^" = "plugin:bmux.windows:last-window"
arrow_down = "plugin:bmux.windows:focus-pane-in-direction --direction down"
arrow_left = "plugin:bmux.windows:focus-pane-in-direction --direction left"
arrow_right = "plugin:bmux.windows:focus-pane-in-direction --direction right"
arrow_up = "plugin:bmux.windows:focus-pane-in-direction --direction up"
"ctrl+e" = "scroll_down_line"
"ctrl+y" = "scroll_up_line"
d = "detach"
g = "scroll_top"
h = "plugin:bmux.windows:focus-pane-in-direction --direction left"
j = "plugin:bmux.windows:focus-pane-in-direction --direction down"
k = "plugin:bmux.windows:focus-pane-in-direction --direction up"
l = "plugin:bmux.windows:focus-pane-in-direction --direction right"
minus = "plugin:bmux.windows:resize-pane --direction decrease"
o = "plugin:bmux.windows:focus-pane-in-direction --direction next"
page_down = "scroll_down_page"
page_up = "scroll_up_page"
plus = "plugin:bmux.windows:resize-pane --direction increase"
q = "quit"
r = "plugin:bmux.windows:restart-pane"
"shift+arrow_down" = "plugin:bmux.windows:resize-pane --direction down"
"shift+arrow_left" = "plugin:bmux.windows:resize-pane --direction left"
"shift+arrow_right" = "plugin:bmux.windows:resize-pane --direction right"
"shift+arrow_up" = "plugin:bmux.windows:resize-pane --direction up"
"shift+c" = "plugin:bmux.sessions:new-session"
"shift+g" = "scroll_bottom"
"shift+h" = "plugin:bmux.windows:resize-pane --direction left"
"shift+j" = "plugin:bmux.windows:resize-pane --direction down"
"shift+k" = "plugin:bmux.windows:resize-pane --direction up"
"shift+l" = "plugin:bmux.windows:resize-pane --direction right"
v = "begin_selection"
x = "plugin:bmux.windows:close-active-pane"
z = "plugin:bmux.windows:zoom-pane"
Default global bindings
[keybindings.global]
"alt+0" = "plugin:bmux.windows:goto-window 10"
"alt+1" = "plugin:bmux.windows:goto-window 1"
"alt+2" = "plugin:bmux.windows:goto-window 2"
"alt+3" = "plugin:bmux.windows:goto-window 3"
"alt+4" = "plugin:bmux.windows:goto-window 4"
"alt+5" = "plugin:bmux.windows:goto-window 5"
"alt+6" = "plugin:bmux.windows:goto-window 6"
"alt+7" = "plugin:bmux.windows:goto-window 7"
"alt+8" = "plugin:bmux.windows:goto-window 8"
"alt+9" = "plugin:bmux.windows:goto-window 9"
"alt+=" = "plugin:bmux.windows:resize-pane --direction increase"
"alt+down" = "plugin:bmux.windows:focus-pane-in-direction --direction down"
"alt+h" = "plugin:bmux.windows:focus-pane-in-direction --direction left"
"alt+j" = "plugin:bmux.windows:focus-pane-in-direction --direction down"
"alt+k" = "plugin:bmux.windows:focus-pane-in-direction --direction up"
"alt+left" = "plugin:bmux.windows:focus-pane-in-direction --direction left"
"alt+minus" = "plugin:bmux.windows:resize-pane --direction decrease"
"alt+n" = "plugin:bmux.windows:split-pane --direction horizontal"
"alt+plus" = "plugin:bmux.windows:resize-pane --direction increase"
"alt+right" = "plugin:bmux.windows:focus-pane-in-direction --direction right"
"alt+t" = "plugin:bmux.windows:focus-pane-in-direction --direction next"
"alt+up" = "plugin:bmux.windows:focus-pane-in-direction --direction up"
"ctrl+alt+t" = "plugin:bmux.theme:pick-theme"
"ctrl+h" = "plugin:bmux.windows:prev-window"
"ctrl+j" = "plugin:bmux.windows:prev-window"
"ctrl+k" = "plugin:bmux.windows:focus-pane-in-direction --direction prev"
"ctrl+l" = "plugin:bmux.windows:last-window"
"ctrl+left" = "plugin:bmux.windows:prev-window"
"ctrl+o" = "plugin:bmux.windows:last-window"
"ctrl+right" = "plugin:bmux.windows:next-window"
"ctrl+s" = "plugin:bmux.windows:next-window"
"ctrl+t" = "plugin:bmux.windows:focus-pane-in-direction --direction prev"
Default scroll bindings
[keybindings.scroll]
arrow_down = "move_cursor_down"
arrow_left = "move_cursor_left"
arrow_right = "move_cursor_right"
arrow_up = "move_cursor_up"
"ctrl+a ]" = "exit_scroll_mode"
"ctrl+b" = "scroll_up_page"
"ctrl+c" = "exit_scroll_mode"
"ctrl+e" = "scroll_down_line"
"ctrl+y" = "scroll_up_line"
enter = "confirm_scrollback"
escape = "exit_scroll_mode"
g = "scroll_top"
h = "move_cursor_left"
j = "move_cursor_down"
k = "move_cursor_up"
l = "move_cursor_right"
page_down = "scroll_down_page"
page_up = "scroll_up_page"
"shift+g" = "scroll_bottom"
v = "begin_selection"
y = "copy_scrollback"
[plugins]
Plugin discovery, enablement, and per-plugin settings
| Option | Type | Default | Description |
| enabled | list of strings | (empty) | Plugin IDs to enable in addition to the bundled defaults. Bundled plugins like bmux.windows and bmux.permissions are enabled automatically without being listed here. |
| disabled | list of strings | (empty) | Plugin IDs to explicitly disable, including bundled ones. Overrides both bundled defaults and the enabled list. |
| search_paths | list of paths | (empty) | Additional directories to scan for plugin binaries beyond the default plugin search path. Supports ~, $VAR, and ${VAR} interpolation. |
| settings | table | (empty) | Per-plugin settings keyed by plugin ID. Each plugin defines its own accepted keys and values. |
| native_service.initial_response_bytes | integer | 4096 | Initial response buffer size, in bytes, for native service calls. |
| native_service.max_response_bytes | integer | 67108864 | Maximum response buffer size, in bytes, for native service calls. |
| native_service.buffer_resize_attempts | integer | 8 | Maximum number of buffer-too-small retries before failing the service call. Set to 0 to disable retries beyond the initial buffer. |
| routing.conflict_mode | string (fail_startup) | fail_startup | Conflict behavior when multiple plugins claim overlapping command ownership. |
| routing.required_namespaces.<index>.namespace | string | (empty) | Namespace segment that must be owned by a plugin. |
| routing.required_namespaces.<index>.owner | string (optional) | — | Optional owner plugin ID; when omitted, any plugin may own the namespace. |
| routing.required_paths.<index>.path | list of strings | (empty) | Command path that must be owned by a plugin. |
| routing.required_paths.<index>.owner | string (optional) | — | Optional owner plugin ID; when omitted, any plugin may own the path. |
[connections]
Local and remote connection target profiles
| Option | Type | Default | Description |
| hosted_mode | string (p2p, control_plane) | p2p | Hosted mode strategy. p2p avoids control-plane dependencies by default. |
| default_target | string (optional) | — | Default command target when --target is not passed. |
| control_plane_url | string (optional) | — | Optional control-plane base URL for hosted auth/share resolution. |
| targets.<name>.transport | string (local, ssh, tls, iroh) | local | Transport backend for this target. |
| targets.<name>.host | string (optional) | — | SSH host for transport = "ssh". |
| targets.<name>.user | string (optional) | — | SSH username override. |
| targets.<name>.port | integer (optional) | — | SSH port override. |
| targets.<name>.identity_file | path (optional) | — | Private key file path. Supports ~, $VAR, and ${VAR} interpolation. |
| targets.<name>.known_hosts_file | path (optional) | — | Known hosts file path. Supports ~, $VAR, and ${VAR} interpolation. |
| targets.<name>.ca_file | path (optional) | — | Optional CA certificate bundle used for TLS transport. Supports ~, $VAR, and ${VAR} interpolation. |
| targets.<name>.server_name | string (optional) | — | Optional TLS server name override (defaults to host). |
| targets.<name>.endpoint_id | string (optional) | — | Iroh endpoint id for hosted transport. |
| targets.<name>.relay_url | string (optional) | — | Optional Iroh relay URL for hosted transport. |
| targets.<name>.iroh_ssh_auth | bool | false | Require SSH auth handshake when connecting to this iroh target. |
| targets.<name>.strict_host_key_checking | bool | true | Require strict host key checking. |
| targets.<name>.jump | string (optional) | — | SSH jump host (ProxyJump) value. |
| targets.<name>.remote_bmux_path | string | bmux | Remote bmux executable path. |
| targets.<name>.connect_timeout_ms | integer | 8000 | Connection timeout in milliseconds. |
| targets.<name>.server_start_mode | string (auto, require_running) | auto | Remote server startup behavior. |
| targets.<name>.default_session | string (optional) | — | Default session name used by clients. |
| recent_targets | list of strings | (empty) | Most recently used targets (newest first). |
| recent_sessions | table | (empty) | Most recently used sessions per target (newest first). |
| share_links | table | (empty) | User-defined share links (bmux:// |
| iroh_ssh_access.enabled | bool | false | Require SSH challenge authentication on iroh connections. |
| iroh_ssh_access.allowlist.<fingerprint>.public_key | string | (empty) | Public key in OpenSSH one-line format. |
| iroh_ssh_access.allowlist.<fingerprint>.label | string (optional) | — | Optional descriptive label (for display and management UX). |
| iroh_ssh_access.allowlist.<fingerprint>.added_at_unix | integer (optional) | — | Unix timestamp of when the key was added. |
[status_bar]
Content and layout of the status bar displayed at the top or bottom of the terminal
| Option | Type | Default | Description |
| enabled | bool | true | Enable status bar rendering in attach UI. |
| preset | string (tab_rail, minimal, classic) | tab_rail | High-level status bar visual preset. |
| layout.density | string (compact, cozy) | cozy | Spacing density for tabs and right modules. |
| layout.left_padding | integer | 1 | Left padding before first tab. |
| layout.right_padding | integer | 1 | Right padding after final segment. |
| layout.tab_gap | integer | 1 | Number of spaces between tabs. |
| layout.module_gap | integer | 1 | Number of spaces between right-side modules. |
| layout.overflow_style | string (count, arrows) | arrows | Overflow indicator style when tabs are hidden. |
| layout.align_active | string (keep_visible, focus_bias) | keep_visible | Behavior used to keep the active tab visible. |
| style.separator_set | string (angled_segments, plain, ascii) | angled_segments | Separator character set for tabs and modules. |
| style.prefer_unicode | bool | true | Prefer Unicode separators when available. |
| style.force_ascii | bool | false | Force ASCII separators even when Unicode is enabled. |
| style.dim_inactive | bool | true | Dim inactive tabs for stronger active emphasis. |
| style.bold_active | bool | true | Bold active tabs for stronger active emphasis. |
| style.underline_active | bool | false | Underline active tabs. |
| colors.bar_bg | string (optional) | — | Bar background color (hex #RRGGBB). |
| colors.bar_fg | string (optional) | — | Bar foreground color (hex #RRGGBB). |
| colors.tab_active_bg | string (optional) | — | Active tab background color (hex #RRGGBB). |
| colors.tab_active_fg | string (optional) | — | Active tab foreground color (hex #RRGGBB). |
| colors.tab_inactive_bg | string (optional) | — | Inactive tab background color (hex #RRGGBB). |
| colors.tab_inactive_fg | string (optional) | — | Inactive tab foreground color (hex #RRGGBB). |
| colors.module_bg | string (optional) | — | Right-side module background color (hex #RRGGBB). |
| colors.module_fg | string (optional) | — | Right-side module foreground color (hex #RRGGBB). |
| colors.overflow_bg | string (optional) | — | Overflow marker background color (hex #RRGGBB). |
| colors.overflow_fg | string (optional) | — | Overflow marker foreground color (hex #RRGGBB). |
| max_tabs | integer | 12 | Maximum number of tabs shown in the tab strip before overflow is collapsed. |
| tab_label_max_width | integer | 20 | Maximum display width for each tab label. |
| show_tab_index | bool | true | Display 1-based tab indexes before labels. |
| tab_scope | string (all_contexts, session_contexts, mru) | all_contexts | Which context set to render as tabs. |
| tab_order | string (stable, mru) | stable | How tab entries are ordered when rendered. |
| show_session_name | bool | false | Display the active session name in the status bar. |
| show_context_name | bool | false | Display the current context label in the status bar. |
| show_mode | bool | true | Display the current interaction mode (Normal, Scroll, Help, etc.). |
| show_role | bool | true | Display the current attach role (write/read-only). |
| show_follow | bool | true | Display follow target details when following another client. |
| show_hint | bool | true | Display runtime hints on the right side. |
| hint_policy | string (always, scroll_only, never) | scroll_only | Hint visibility policy. |
Status Bar Preset Examples
Tab Rail (recommended)
[status_bar]
enabled = true
preset = "tab_rail"
tab_scope = "all_contexts"
tab_order = "stable"
max_tabs = 14
tab_label_max_width = 22
show_tab_index = true
show_mode = true
show_role = true
show_follow = true
show_hint = true
hint_policy = "scroll_only"
[status_bar.layout]
density = "cozy"
left_padding = 1
right_padding = 1
tab_gap = 1
module_gap = 1
overflow_style = "arrows"
align_active = "keep_visible"
[status_bar.style]
separator_set = "angled_segments"
prefer_unicode = true
force_ascii = false
dim_inactive = true
bold_active = true
underline_active = false
Minimal
[status_bar]
enabled = true
preset = "minimal"
tab_scope = "all_contexts"
tab_order = "stable"
show_tab_index = false
show_follow = false
show_hint = true
hint_policy = "scroll_only"
[status_bar.layout]
density = "compact"
tab_gap = 1
module_gap = 1
overflow_style = "count"
align_active = "keep_visible"
[status_bar.style]
separator_set = "plain"
prefer_unicode = false
force_ascii = true
dim_inactive = true
bold_active = false
underline_active = false
Status Color Override (partial)
[status_bar.colors]
# Unset fields inherit from the runtime appearance defaults
tab_active_bg = "#7aa2f7"
tab_active_fg = "#1a1b26"
tab_inactive_bg = "#2a2f45"
module_bg = "#343a55"
[recording]
Session recording for terminal replay, debugging, and playbook generation
| Option | Type | Default | Description |
| dir | path (optional) | — | Root directory for recording data. Supports ~, $VAR, and ${VAR} interpolation. Relative paths are resolved against the directory containing bmux.toml. |
| enabled | bool | true | Enable hidden rolling recording by default when the server starts. Manual recordings (bmux recording start/stop) remain available even when this is false. |
| capture_input | bool | true | Capture pane input bytes (keystrokes sent to pane processes) |
| capture_output | bool | true | Capture pane output bytes (terminal output from pane processes) |
| capture_events | bool | true | Capture lifecycle and server events (pane creation, resize, close, etc.) |
| rolling_capture_input | bool (optional) | — | Override rolling capture of pane input bytes. None falls back to recording.capture_input. |
| rolling_capture_output | bool (optional) | — | Override rolling capture of pane output bytes. None falls back to recording.capture_output. |
| rolling_capture_events | bool (optional) | — | Override rolling capture of lifecycle/request/custom events. None falls back to recording.capture_events. |
| rolling_capture_protocol_replies | bool (optional) | — | Enable rolling capture of protocol reply bytes. None defaults to false. |
| rolling_capture_images | bool (optional) | — | Enable rolling capture of extracted pane image payloads. None defaults to false. |
| rolling_event_kinds | list of strings (pane_input_raw, pane_output_raw, protocol_reply_raw, pane_image, server_event, request_start, request_done, request_error, custom) | (empty) | Explicit rolling event-kind allowlist. When non-empty, this takes precedence over rolling capture category booleans. |
| segment_mb | integer | 64 | Rotate recording segments at approximately this size in MB |
| retention_days | integer | 30 | Retention period for completed recordings in days. Set to 0 to disable automatic pruning and keep recordings indefinitely. |
| rolling_window_secs | integer | 0 | Enable hidden always-on rolling capture and retain at most this many seconds of recent events. Set to 0 to disable rolling capture. |
| auto_export | bool | false | Automatically export stopped/cut user-initiated recordings as GIF. |
| auto_export_dir | path (optional) | — | Directory for auto-exported GIFs. Supports ~, $VAR, and ${VAR} interpolation. Relative paths are resolved against the directory containing bmux.toml. When unset, GIFs are written next to the recording directory. |
| export.fps | integer | 24 | Target frames per second default for GIF exports. |
| export.cursor | string (auto, on, off) | auto | Cursor rendering default for recording export. |
| export.cursor_shape | string (auto, block, bar, underline) | auto | Cursor shape default for recording export. |
| export.cursor_blink | string (auto, on, off) | auto | Cursor blink default for recording export. |
| export.cursor_blink_period_ms | integer | 500 | Cursor blink period default for recording export. |
| export.cursor_color | string | auto | Cursor color default for recording export (auto or #RRGGBB). |
| export.cursor_profile | string (auto, ghostty, generic) | auto | Cursor behavior profile default for recording export. |
| export.cursor_solid_after_activity_ms | integer (optional) | — | Keep cursor solid after activity for this duration in milliseconds. None lets terminal profiles choose an emulator-specific default. |
| export.cursor_solid_after_input_ms | integer (optional) | — | Keep cursor solid after input activity for this duration in milliseconds. |
| export.cursor_solid_after_output_ms | integer (optional) | — | Keep cursor solid after output activity for this duration in milliseconds. |
| export.cursor_solid_after_cursor_ms | integer (optional) | — | Keep cursor solid after cursor movement activity for this duration in milliseconds. |
| export.cursor_paint_mode | string (auto, invert, fill, outline) | auto | Cursor paint mode default for recording export. |
| export.cursor_text_mode | string (auto, swap_fg_bg, force_contrast) | auto | Cursor text mode default for recording export. |
| export.cursor_bar_width_pct | integer | 16 | Cursor bar width default as a percent of cell width. |
| export.cursor_underline_height_pct | integer | 12 | Cursor underline height default as a percent of cell height. |
| export.palette_source | string (auto, recording, terminal, xterm) | auto | Palette source default for recording export. |
| export.palette_foreground | string (optional) | — | Default foreground override for recording export palette resolution. Accepts auto/empty to keep source-derived defaults, or a color value. |
| export.palette_background | string (optional) | — | Default background override for recording export palette resolution. Accepts auto/empty to keep source-derived defaults, or a color value. |
| export.palette_colors | list of strings | (empty) | Default indexed color overrides for recording export. Entries must be INDEX=COLOR (for example 5=#bb78d9). |
[performance]
Performance diagnostics capture controls and telemetry safety limits
| Option | Type | Default | Description |
| recording_level | string (off, basic, detailed, trace) | off | Capture verbosity for performance telemetry written into recording custom events. |
| window_ms | integer | 1000 | Aggregation window for periodic performance telemetry, in milliseconds. |
| max_events_per_sec | integer | 32 | Maximum number of performance custom events emitted per second by a client/runtime. |
| max_payload_bytes_per_sec | integer | 65536 | Maximum serialized performance payload bytes emitted per second by a client/runtime. |
[logs]
Runtime diagnostic log rotation, retention, and sink selection
| Option | Type | Default | Description |
| retention_days | integer | 14 | Default completed-log retention for sinks that do not override it. |
| max_total_mb | integer | 1024 | Default maximum total disk usage in MiB for sinks that do not override it. |
| prune_interval_secs | integer | 3600 | Background prune cadence in seconds for long-running processes. |
| server.mode | string (segmented, unified, off) | segmented | Sink mode: segmented, unified, or off. |
| server.segment_mb | integer | 16 | Segment rotation size in MiB. |
| server.retention_days | integer | 14 | Completed-run retention in days. |
| server.max_total_mb | integer | 512 | Maximum total disk usage in MiB. |
| client.mode | string (segmented, unified, off) | segmented | Sink mode: segmented, unified, or off. |
| client.diagnostic_level | string (basic, detailed, trace) | basic | Diagnostic event verbosity. |
| client.segment_mb | integer | 8 | Segment rotation size in MiB. |
| client.retention_days | integer | 7 | Completed-run retention in days. |
| client.max_total_mb | integer | 256 | Maximum total disk usage in MiB. |
| client.slow_frame_ms | integer | 50 | Slow frame warning threshold in milliseconds. |
| client.slow_terminal_write_ms | integer | 25 | Slow terminal write warning threshold in milliseconds. |
| client.metrics_window_ms | integer | 1000 | Metrics summary window in milliseconds. |
[kiosk]
Kiosk profiles and SSH/bootstrap settings for locked-down access flows
| Option | Type | Default | Description |
| defaults.enabled | bool | false | Enable kiosk features and commands. |
| defaults.ssh_user | string | bmux-kiosk | Default SSH user when profiles do not override it. |
| defaults.role | string (observer, writer) | observer | Default role assigned to issued kiosk tokens. |
| defaults.allow_detach | bool | false | Allow detach in kiosk attach mode. |
| defaults.token_ttl_secs | integer | 900 | Default issued token TTL in seconds. |
| defaults.one_shot | bool | true | Require one-time token usage by default. |
| defaults.sandbox | string (auto, none, container, native) | auto | Sandbox mode preference. |
| profiles.<name>.session | string (optional) | — | Optional session name to attach when token omits a session override. |
| profiles.<name>.target | string (optional) | — | Optional target name for attach routing. |
| profiles.<name>.role | string (optional) | — | Override role for this profile. |
| profiles.<name>.ssh_user | string (optional) | — | Override SSH user for this profile. |
| profiles.<name>.allow_detach | bool (optional) | — | Override detach policy for this profile. |
| profiles.<name>.token_ttl_secs | integer (optional) | — | Override token TTL in seconds for this profile. |
| profiles.<name>.one_shot | bool (optional) | — | Override one-shot token behavior for this profile. |
| profiles.<name>.sandbox | string (optional) | — | Override sandbox mode for this profile. |
| files.sshd_include_path | path (optional) | — | Destination path for generated sshd include content. |
| files.wrapper_dir | path (optional) | — | Destination directory for generated wrapper scripts. |
[sandbox]
Sandbox workflow defaults for cleanup and isolation operations
| Option | Type | Default | Description |
| cleanup.failed_only | bool | false | When true, cleanup removes only failed/aborted sandboxes. |
| cleanup.older_than_secs | integer | 300 | Minimum age in seconds before sandbox is eligible for cleanup. |
| cleanup.source | string (sandbox_cli, playbook, recording_verify, all) | all | Default cleanup source scope. |