[Tracking Issue] Cross-platform window appearance override
AI-disclosure: drafted with AI, manually reviewed and iterated on by me.
Background
Today, WezTerm's window can only follow the system-wide appearance — there's no way to force the window itself to light or dark independently of what the OS reports.
This is a real pain point:
- #5873
- #6767
On the Lua API side, WezTerm exposes this same OS-reported appearance through two calls, wezterm.gui.get_appearance() and window:get_appearance().
Both currently return the exact same live value — the raw OS-reported appearance.
Two separate PRs tried to add the override users are asking for, per-platform:
- #6876 — adds
win32_window_appearance(Windows only) - #6521 — adds
macos_window_appearance(macOS only)
Both land the override by patching platform-specific window/appearance code, without addressing that this introduces a genuinely new distinction that doesn't exist today: the real OS setting (which should always reflect what the OS reports, live) versus the window's actual rendered appearance (which should honor the override when one is set).
Proposal
Unify the two per-OS PRs into one cross-platform setting covering Windows, macOS, and X11/Wayland:
config.window_appearance = "ForcedDark" -- or "ForcedLight" or "System"
-- defaults to "System" for backward compatibilityThe Forced prefix makes the override intent explicit.
On the Lua API side, no new API needed. Instead, we can change the semantics a little for the existing functiont without breaking backward compatibility:
wezterm.gui.get_appearance()keeps today's behavior unchanged — always the live, system-wide OS value, never affected by the override. (This is what scripts already use to auto-switchcolor_scheme, and that behavior will keep working even while an override is active)window:get_appearance()gains new behavior ✨: it honorswindow_appearancewhen set, returning the override instead of the raw OS value. This is a deliberate divergence fromwezterm.gui.get_appearance(), introduced specifically by this change.
Docs will need updating to make this new distinction more prominent, since today window:get_appearance()'s own doc just says "you probably want wezterm.gui.get_appearance() instead, it's easier to use" — that guidance stops being universally true once an override exists, and needs a callout explaining when each one is the right call.
Closed questions
- Does the override need to synthesize an appearance-changed event on config reload, so anything watching
window:get_appearance()reacts immediately? ANSWER: Not useful, the config should already get reloaded in this case so user can do what they want
Source: wezterm/wezterm