sync-panes.wez

June 10, 2026 · View on GitHub

A WezTerm plugin that mirrors your keystrokes to every pane in the active tab — the equivalent of tmux's synchronize-panes. Toggle it on, type once, and the same input lands in all panes at the same time.

Features

  • One-key toggle — turn synchronization on/off per GUI window (default CTRL+SHIFT+E).
  • Status indicator — an optional ⟳ SYNC badge in the right status bar while sync is active.
  • Border highlight — optionally recolor the window border and pane split lines while sync is active for a second, hard-to-miss visual cue.
  • Broadcasts everything you'd expect — printable characters, Ctrl/Alt combinations, Enter/Tab/Backspace/Escape, arrow & navigation keys, and F1F12.
  • Survives config reloads — enabled state is stored in wezterm.GLOBAL, so reloading your config won't drop you out of sync mode.
  • Configurable — change the toggle key, key-table name, indicator text and color, the border highlight color, and the Backspace byte.

Requirements

A recent version of WezTerm — any build that includes the wezterm.plugin API.

Installation

WezTerm plugins are loaded straight from a git URL. Add this to your wezterm.lua:

local sync = wezterm.plugin.require("https://github.com/annie444/sync-panes.wez")

WezTerm clones and caches the plugin automatically on next launch.

Quick start

local wezterm = require("wezterm")
local config = wezterm.config_builder()

local sync = wezterm.plugin.require("https://github.com/annie444/sync-panes.wez")
sync.apply_to_config(config)

return config

That's it. Press CTRL+SHIFT+E to toggle synchronization for the current window. While it's on, the ⟳ SYNC indicator appears at the right of the status bar and every key you type is sent to all panes in the tab.

Configuration

Pass an options table as the second argument to apply_to_config. Every field is optional and falls back to the default below.

OptionDefaultDescription
key_table_name"sync_mode"Name of the key table the plugin generates.
toggle_key"E"Key that toggles synchronization.
toggle_mods"CTRL|SHIFT"Modifiers for the toggle key. Must not collide with a mirrored key (see Caveats).
indicatorfalseShow the right-status indicator while sync is active. Set false to manage it yourself.
status_text"⟳ SYNC"Text shown in the indicator.
indicator_color"Red"Color for the indicator text (ANSI color name or #rrggbb hex).
borderfalseRecolor the window border and pane splits while sync is active. Set true to enable.
border_color"Red"Color for the border and pane splits while sync is active (used when border = true).
backspace"\127"Byte(s) sent for Backspace. 0x7f (DEL) is the common default; use "\8" for ^H.

Example

sync.apply_to_config(config, {
  toggle_key = "S",
  toggle_mods = "CTRL|SHIFT",
  status_text = "BROADCAST",
  indicator = true,
  indicator_color = "Yellow",
  border = true,
  border_color = "Yellow",
})

Usage

  • Press the toggle key (default CTRL+SHIFT+E) to start or stop synchronizing.
  • Synchronization is per GUI window — toggling one window doesn't affect another.
  • While active, anything you type is sent to every pane in the active tab, including the pane you're typing in (so there's no double input).
  • Control sequences are broadcast too: pressing Ctrl+C while synced sends an interrupt to all panes at once.

Integrating with tabline

If you use tabline.wez, you can show the sync state in tabline's status bar instead of the plugin's own right-status indicator — no extra wiring required. tabline's built-in mode component reads the active WezTerm key table, and this plugin's table is named sync_mode, so while sync is active the mode cell automatically displays SYNC.

  1. Turn off the built-in indicator so the two don't double up:

    sync.apply_to_config(config, { indicator = false })
    
  2. Add 'mode' to a tabline section (skip if it's already there):

    tabline.setup({
      sections = { tabline_a = { 'mode' } },
    })
    
  3. Color it with tabline theme_overrides, keyed by the table name:

    tabline.setup({
      options = {
        theme_overrides = {
          sync_mode = {
            a = { fg = '#1e1e2e', bg = '#f38ba8' },
            b = { fg = '#f38ba8', bg = '#313244' },
            c = { fg = '#cdd6f4', bg = '#1e1e2e' },
          },
        },
      },
      sections = { tabline_a = { 'mode' } },
    })
    

Notes

  • The table name must end in _mode. tabline only treats a key table as a "mode" when its name ends in _mode; otherwise the cell shows NORMAL. The default sync_modeSYNC. To change the label, rename the table while keeping the suffix (e.g. key_table_name = "broadcast_mode"BROADCAST) and match the theme_overrides key to it.
  • status_text and indicator_color don't apply here. Those style the plugin's own right-status indicator only — the tabline label comes from the key table name and tabline's theme.

API

apply_to_config is all most setups need, but the plugin also exposes helpers for custom integrations.

sync.apply_to_config(config, opts?)

Registers the key table and binds the toggle key. Returns the modified config.

sync.is_synced(window)

Returns true if synchronization is currently enabled for the given GUI window. Useful for composing your own status bar when you set indicator = false:

sync.apply_to_config(config, { indicator = false })

wezterm.on("update-status", function(window, _)
  if sync.is_synced(window) then
    window:set_right_status(" SYNC ")
  else
    window:set_right_status("")
  end
end)

sync.toggle

The toggle action itself. Bind it to an additional key if you'd like more than one way to switch sync on and off:

table.insert(config.keys, {
  key = "F5",
  action = sync.toggle,
})

Caveats

  • Toggle key must not be a mirrored key. The key that toggles sync has to fall through the active key table rather than being broadcast. CTRL|SHIFT combinations are never mirrored, which is why the default CTRL+SHIFT+E works. If you pick a different combination, make sure it isn't one of the broadcast keys.
  • Arrow keys use normal cursor mode. Navigation keys are sent as normal-mode (not application-mode) cursor sequences. Full-screen TUIs that switch the terminal into application cursor mode may receive different bytes than they expect for the arrow keys.
  • Backspace defaults to DEL (0x7f). This matches the behavior of the latest WezTerm release. If you're running an older version, set backspace = "\8".

License

MIT