---
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 | |