#8088·wezterm

[Tracking Issue] Cross-platform window appearance override

Author: bewCreated Aug 23, 2026Updated Sep 12, 2026
LabelsenhancementT: lua-apiTracking Issuehas: new config/actionfeedback welcome 🙃

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:

lua
config.window_appearance = "ForcedDark" -- or "ForcedLight" or "System"
-- defaults to "System" for backward compatibility

The 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-switch color_scheme, and that behavior will keep working even while an override is active)
  • window:get_appearance() gains new behavior ✨: it honors window_appearance when set, returning the override instead of the raw OS value. This is a deliberate divergence from wezterm.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

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