--- name: wezterm which: wezterm description: "Use for WezTerm config: Lua, panes, tabs, domains, key bindings, appearance. Use terminal-harness to drive interactive programs." --- # WezTerm Skill WezTerm is a Rust-based GPU-accelerated terminal emulator with a built-in multiplexer, cross-platform (Linux/macOS/Windows/FreeBSD/NetBSD). Configuration uses **Lua 5.4** in `~/.wezterm.lua` or `~/.config/wezterm/wezterm.lua`. **Config file discovery order:** CLI `--config-file` > `$WEZTERM_CONFIG_FILE` > Windows exe dir > `$XDG_CONFIG_HOME/wezterm/wezterm.lua` > `~/.config/wezterm/wezterm.lua` > `~/.wezterm.lua` **Auto-reload:** enabled by default (`automatically_reload_config = true`). Changes take effect without restart. ## Basic Config ```lua local wezterm = require 'wezterm' local config = wezterm.config_builder() config.font = wezterm.font 'JetBrains Mono' config.font_size = 11 config.color_scheme = 'nord' config.enable_tab_bar = false return config ``` ## Config File Location | Priority | Path | | -------- | -------------------------------------------------- | | 1 | `--config-file` CLI argument | | 2 | `$WEZTERM_CONFIG_FILE` env var | | 3 | Windows: exe directory (portable/thumb drive mode) | | 4 | `$XDG_CONFIG_HOME/wezterm/wezterm.lua` | | 5 | `~/.config/wezterm/wezterm.lua` | | 6 | `~/.wezterm.lua` | **Key config options:** ```lua config.automatically_reload_config = true -- default config.config_file = 'path/to/wezterm.lua' -- explicit path ``` ## Colors & Appearance ```lua -- Use a built-in color scheme config.color_scheme = 'nord' -- see wezterm.color.get_builtin_schemes() -- Fully custom colors config.colors = { foreground = '#cccccc', background = '#1e1e1e', cursor_bg = '#ffffff', cursor_border = '#ffffff', cursor_fg = '#1e1e1e', selection_bg = '#264f78', tab_bar = { background = '#0d1117', active_tab = { bg_color = '#161b22', fg_color = '#cccccc' } }, ansi = { '#484848', '#cc4444', '#44cc44', '#cccc44', '#4444cc', '#cc44cc', '#44cccc', '#cccccc' }, brightness = { '#303030', '#e06060', '#60e060', '#e0e060', '#6060e0', '#e060e0', '#60e0e0', '#e0e0e0' }, } ``` **Background layers** (multiple can be combined): ```lua -- Solid background color config.background = { { source = 'solid_color', color = '#0d1117' } } -- Vertical gradient config.background = { { source = 'linear_gradient', orientation = 'Vertical', colors = { '#0d1117', '#161b22' } }, } -- Radial gradient config.background = { { source = 'radial_gradient', anchor = 'bottom', colors = { '#0d1117', '#161b22' } }, } -- Background image config.background = { { source = 'image', path = '/path/to/image.png', hscan = 'Flip', vscan = 'Tile' }, { source = 'solid_color', color = '#0d1117', alpha = 0.7 }, -- overlay } ``` **Window chrome:** ```lua config.window_decorations = 'RESIZE' -- 'RESIZE' | 'MACOS_BORDERLESS' | 'NONE' | 'ALWAYS_FORCE_OPAQUE' config.window_background_opacity = 0.95 config.window_padding = { left = 8, right = 8, top = 0, bottom = 0 } config.hide_tab_bar_if_only_one_tab = true config.use_fancy_tab_bar = false config.tab_bar_at_bottom = false ``` ## Fonts ```lua -- Single font config.font = wezterm.font 'JetBrains Mono' -- With fallback chain config.font = wezterm.font_with_fallback { 'JetBrains Mono', 'Fira Code', 'Noto Sans' } -- Font with size and line height config.font_size = 12 config.line_height = 1.2 config.font_rules = { { italic = true, font = wezterm.font('JetBrains Mono', { italic = true }) }, { weight = 'Bold', font = wezterm.font('JetBrains Mono', { weight = 'Bold' }) }, } ``` **Harfbuzz shaping features:** ```lua config.font_rules = { { intensity = 'Bold', font = wezterm.font('JetBrains Mono', { weight = 'Bold' }), }, { italic = true, font = wezterm.font('JetBrains Mono', { italic = true }), }, } ``` ## Key Bindings ```lua config.keys = { -- Basic keybinding { key = 't', mods = 'CTRL|SHIFT', action = wezterm.action.SpawnTab 'CurrentPaneDomain' }, -- With multiple modifiers { key = 'Enter', mods = 'ALT', action = wezterm.action.ToggleFullScreen }, -- Send string (type text) { key = 'w', mods = 'CTRL|SHIFT', action = wezterm.action.SpawnWindow }, -- Encode special keys { key = 'LeftArrow', mods = 'ALT', action = wezterm.action.EmitEvent 'noop' }, } config.leader = { key = 'a', mods = 'CTRL' } -- chord: Ctrl-a then key ``` **Modifier names:** `CTRL`, `SHIFT`, `ALT`, `SUPER` (macOS Cmd), `CMD`, `META`, `SUPER` **Key names:** single chars, `Enter`, `Escape`, `Space`, `Backspace`, `Tab`, `F1`–`F12`, `LeftArrow`, `RightArrow`, `UpArrow`, `DownArrow`, `Home`, `End`, `PageUp`, `PageDown`, `Insert`, `Delete` **Key tables** for mode switching: ```lua config.key_tables = { copy_mode = { { key = 'Escape', mods = 'NONE', action = wezterm.action.ActivateCopyMode 'Prev' }, { key = 'q', mods = 'NONE', action = wezterm.action.ActivateCopyMode 'Close' }, { key = 'g', mods = 'NONE', action = 'ScrollByPage', args = { -1 } }, { key = 'G', mods = 'SHIFT', action = 'ScrollToBottom' }, { key = 'j', mods = 'NONE', action = 'ScrollByLine', args = { 1 } }, { key = 'k', mods = 'NONE', action = 'ScrollByLine', args = { -1 } }, { key = 'v', mods = 'NONE', action = wezterm.action.CopyMode 'Select' }, { key = 'V', mods = 'SHIFT', action = wezterm.action.CopyMode 'SelectLine' }, { key = 'y', mods = 'NONE', action = wezterm.action.CopyTo 'Clipboard' }, { key = '/', mods = 'NONE', action = wezterm.action.Search { Regex = '', mode = 'CopyMode' } }, }, } ``` ## Key Actions Reference ### Pane Operations ```lua wezterm.action.SplitHorizontal { domain = 'CurrentPaneDomain' } wezterm.action.SplitVertical { domain = 'CurrentPaneDomain' } wezterm.action.SplitPane { program = '/bin/bash', cwd = '/home', domain = 'CurrentPaneDomain' } wezterm.action.CloseCurrentPane { confirm = true } wezterm.action.AdjustPaneSize { direction = 'Down', amount = 3 } wezterm.action.TogglePaneZoomState wezterm.action.PaneSelect { mode = 'Swap' } -- 'Activate' | 'Swap' | 'ForceSelected' | 'Reset' ``` ### Tab Operations ```lua wezterm.action.SpawnTab 'CurrentPaneDomain' wezterm.action.SpawnTab { domain = 'CurrentPaneDomain', program = '/bin/bash', cwd = '/home' } wezterm.action.CloseCurrentTab { confirm = true } wezterm.action.ActivateTab 2 wezterm.action.MoveTab 3 wezterm.action.ShowTabNavigator ``` ### Window Operations ```lua wezterm.action.SpawnWindow wezterm.action.ActivateWindow 0 wezterm.action.SwitchToWorkspace { name = 'main', spawn = { 'wezterm', 'start' } } wezterm.action.ToggleFullScreen wezterm.action.Maximize ``` ### Navigation ```lua wezterm.action.ActivatePaneDirection 'Down' wezterm.action.ActivatePaneDirection 'Left' wezterm.action.ActivatePaneDirection 'Right' wezterm.action.ActivatePaneDirection 'Up' wezterm.action.ActivatePaneByIndex 0 -- 0-indexed wezterm.action.PaneSelect -- interactive wezterm.action.PaneSelect { mode = 'Activate' } ``` ### Text Operations ```lua wezterm.action.SendString 'hello' wezterm.action.SendKey { key = 'Enter' } wezterm.action.Paste 'Clipboard' wezterm.action.CompleteSelection 'Clipboard' wezterm.action.CopyTo 'Clipboard' ``` ### Copy Mode ```lua wezterm.action.ActivateCopyMode 'CopyMode' wezterm.action.CopyMode { preset = 'vim' } -- vim or emacs wezterm.action.ScrollByPage -1 wezterm.action.ScrollByLine 5 wezterm.action.Search { Regex = 'pattern', mode = 'CopyMode' } wezterm.action.QuickSelect ``` ### UI / Overlay ```lua wezterm.action.ShowLauncher { titles = {}, cli_labels = {} } wezterm.action.ShowDebugOverlay wezterm.action.PromptInputLine { description = 'Enter command', action = wezterm.action_callback(function(window, pane, line) if line then window:perform_action(wezterm.action.SendString(line), pane) end end), } wezterm.action.InputSelector { description = 'Select option', choices = { { label = 'opt1', id = '1' } }, action = wezterm.action_callback(function(window, pane, id, label) end), } ``` ### Multiple / Chaining ```lua wezterm.action.Multiple { wezterm.action.SplitHorizontal { domain = 'CurrentPaneDomain' }, wezterm.action.ActivatePaneDirection 'Right', } ``` ### Other Actions ```lua wezterm.action.EmitEvent 'my-event-name' wezterm.action.ReloadConfiguration wezterm.action.QuitApplication wezterm.action.CharSelect { copy_on_select = true, } ``` ## Lua API Modules ### wezterm module ```lua wezterm.action(action_obj) -- perform an action wezterm.action_callback(fn) -- callback(fn(window, pane, ...)) -> action wezterm.config_builder() -- returns config table wezterm.default_hyperlink_rules() -- returns hyperlink rules wezterm.font(name, opts) -- font with optional weight/italic/slant wezterm.font_with_fallback({'Font1', 'Font2'}) wezterm.format({ { Foreground = { Color = 'red' }, Text = 'hello' } }) wezterm.glob(pattern) -- glob expansion wezterm.json_encode(val) -- JSON string wezterm.json_parse(str) -- parse JSON wezterm.log_error(msg) wezterm.log_info(msg) wezterm.log_warn(msg) wezterm.nerdfonts -- table of icon names wezterm.now() -- Unix timestamp wezterm.on('event', fn) -- register event handler wezterm.read_dir(dir) -- list directory entries wezterm.reload_configuration() wezterm.run_child_process(cmd) -- returns { stdout, stderr, exit_code } wezterm.sleep_ms(ms) wezterm.strftime(fmt, ts) -- format timestamp ``` **Programmatic config reload:** ```lua wezterm.on('window-config-reloaded', function(window) wezterm.log_info('config reloaded for ' .. window:panel():get_title()) end) ``` ### wezterm.color ```lua wezterm.color.parse('#ff0000') -- returns { r=1, g=0, b=0, a=1 } wezterm.color.from_hsla(180, 0.5, 0.5, 1.0) -- returns Color wezterm.color.gradient({'#red', 'blue'}, 'horizontal', 10) -- interpolate colors wezterm.color.get_builtin_schemes() -- list all built-in schemes wezterm.color.load_scheme('nord') -- load scheme as color table wezterm.color.extract_colors_from_image('/path/to/image.png') -- extract palette ``` ### wezterm.gui ```lua wezterm.gui.get_appearance() -- 'Dark' | 'Light' | 'Unknown' wezterm.gui.screens() -- list screens: { { width, height, xscale, yscale, name } } wezterm.gui.enumerate_gpus() -- list available GPUs wezterm.gui.default_keys() -- default keybindings as table wezterm.gui.default_key_tables() -- default key tables (copy mode, etc.) wezterm.gui.gui_windows() -- all GUI windows ``` **Dark/light mode switching:** ```lua wezterm.on('update-status', function(window, pane) local appearance = wezterm.gui.get_appearance() local scheme = appearance == 'Dark' and 'nord' or 'nord-light' window:configure_actions({ { SetColorScheme = scheme }, }) end) ``` ### wezterm.mux ```lua wezterm.mux.spawn_window({ domain = 'local', workspace = 'main', cwd = '/home' }) wezterm.mux.get_active_workspace() -- current workspace name wezterm.mux.all_windows() -- all mux windows wezterm.mux.rename_workspace(old_name, new_name) wezterm.mux.set_active_workspace(name) ``` **Window/Pane objects:** ```lua window:gui_window() -- GuiWindow window:mux_window() -- MuxWindow pane:split({ program = '/bin/bash', domain = 'CurrentPaneDomain' }) pane:send_text('text\n') pane:paste() pane:get_title() pane:get_current_working_dir() -- returns Path or nil pane:get_foreground_process_info() -- returns ProcessInfo { pid, name, cwd } pane:get_text_from_region(0, 0, 100, 200) -- get text rectangle pane:inject_output('text\n') ``` ### wezterm.plugin ```lua wezterm.plugin.require('github.com/path/to/plugin') -- load plugin wezterm.plugin.list() -- list loaded plugins wezterm.plugin.update_all() -- update all plugins ``` ## Events | Event | Callback | | ------------------------ | ------------------------------------- | | `gui-startup` | `fn(window)` | | `gui-attached` | `fn(window)` | | `mux-startup` | `fn()` | | `format-tab-title` | `fn(tab, tabs, panes, config, hover)` | | `format-window-title` | `fn(window)` | | `update-status` | `fn(window, pane)` | | `update-right-status` | `fn(window, pane)` | | `window-config-reloaded` | `fn(window)` | | `window-focus-changed` | `fn(window, bool)` | | `window-resized` | `fn(window, size)` | | `bell` | `fn(window, pane)` | | `open-uri` | `fn(uri, action)` | | `user-var-changed` | `fn(pane, name, value)` | **Example — dynamic tab titles:** ```lua wezterm.on('format-tab-title', function(tab, tabs, panes, config, hover) return tab.tab_index + 1 .. ': ' .. tab.active_pane.title end) ``` **Example — status line:** ```lua wezterm.on('update-right-status', function(window, pane) window:set_right_status(wezterm.format { { Text = wezterm.strftime('%H:%M:%S') }, }) end) ``` ## Multiplexing & Domains ```lua config.unix_domains = { { name = 'unix', socket_dir = '/tmp/wezterm' } } config.ssh_domains = { { name = 'prod-server', host = 'example.com', username = 'me', port = 22, -- or use SSH config: remote_addr = 'example.com' ssh_option = 'value', }, } config.wsl_domains = { { name = 'WSL:Ubuntu', distribution = 'Ubuntu' } } config.tls_domains = { { name = 'tls-server', host = 'example.com', port = 443 } } ``` **Spawning in domains:** ```lua { key = 'c', mods = 'CTRL|SHIFT', action = wezterm.action.SpawnCommandInDomain { domain = 'unix', program = '/bin/bash' } } ``` ## CLI Reference Use `terminal-harness` for pane control, app input, and screen capture. This section covers configuration-adjacent commands only. ```bash # Launch GUI wezterm start wezterm start --config-file ~/.wezterm.lua wezterm start --prefix-search 'ssh' # SSH wezterm ssh user@host wezterm ssh user@host --domian-name prod # Connect to domain wezterm connect domain-name # Titles wezterm cli set-tab-title --pane-id 1 "My Tab" wezterm cli set-window-title --window-id 0 "My Window" wezterm cli rename-workspace --name main # Utilities wezterm show-keys --help # key sequence explorer wezterm ls-fonts # list available fonts wezterm imgcat /path/to/image.png # display image wezterm serial /dev/ttyUSB0 115200 wezterm record --label "session" # record session wezterm replay /path/to/recording # replay ``` **CLI flags for `wezterm start`:** ```bash wezterm start --config-file FILE wezterm start --cwd DIR wezterm start --position X,Y wezterm start --size WIDTH,HEIGHT wezterm start --domain SOCKET_DIR wezterm start --workspace NAME ``` ## Common Patterns **Dark/light mode colors:** ```lua local function get_colors() local appearance = wezterm.gui.get_appearance() local scheme = appearance == 'Dark' and 'nord' or 'nord-bright' return wezterm.color.load_scheme(scheme) end wezterm.on('update-status', function(window, pane) local colors = get_colors() pane:set_config_overrides { colors = { foreground = colors.foreground, background = colors.background }, } end) ``` **Gradient background with overlay:** ```lua config.background = { { source = 'linear_gradient', orientation = 'Vertical', colors = { '#0d1117', '#161b22' } }, { source = 'solid_color', color = '#000000', width = '100%', opacity = 0.3, fill = 'Gradient' }, } ``` **Workspace-aware status:** ```lua wezterm.on('format-window-title', function(window) local workspace = wezterm.mux.get_active_workspace() return workspace .. ' — ' .. window:gui_window().title end) ``` **Conditional action with callback:** ```lua wezterm.on('update-status', function(window, pane) local has_jobs = #pane:get_foreground_process_info() > 0 window:perform_action( has_jobs and wezterm.action.ShowTabNavigator() or wezterm.action_callback(function() end), pane ) end) ``` ## URL Reference | Topic | URL | | --------------------- | ----------------------------------------------- | | Main docs | | | Config overview | | | Lua config options | | | Lua API reference | | | Color module | | | GUI module | | | Mux module | | | KeyAssignment actions | | | Window events | | | GUI events | | | CLI reference | | | Key binding config | | | Key tables | | | Default keys | | | Launching programs | | | Plugin system | | | Mouse bindings | | | Color schemes | |