How to Switch Between Dark and Light#

Every one of the 24 targets renders both modes, and every role in semantics.yaml/ anchors/*.yaml resolves under both — but “the artifact exists” and “your terminal is showing it” are two different problems. This covers the switch itself: how mode is selected, which tools honor that selection automatically, and how to get each application to actually pick up its light half.

Two independent --mode flags#

Irix has two unrelated things both called --mode, and confusing them is the most common way to be surprised:

  • The four interactive CLIs — colorcode, promptcode, kittyhud, themecode — resolve a runtime mode through irix.term.resolve_mode, with a fixed precedence:

    1. An explicit --mode {dark,light} flag, if given.

    2. $IRIX_MODE, if set.

    3. dark, otherwise.

    An invalid value from either source prints one warning to stderr and falls back to dark — color-mode selection is never allowed to crash a shell prompt.

  • irix generate / irix check / irix deploy take their own --mode {dark,light,both} (default both). This selects which mode’s artifacts to render, diff, or copy — it has nothing to do with $IRIX_MODE, doesn’t read it, and isn’t read by it. Setting $IRIX_MODE=light in your environment has zero effect on irix generate; you’d pass irix generate --mode light explicitly.

IRIX_MODE=light uv run promptcode --path . --fmt plain   # picks up $IRIX_MODE
uv run promptcode --path . --fmt ansi --mode dark          # explicit flag wins regardless
uv run irix generate kitty --mode light                    # unrelated flag, unrelated tool

For an interactive session, the simplest approach is exporting it once:

export IRIX_MODE=light

and every colorcode/promptcode/kittyhud/themecode invocation in that shell follows, with no per-command flag needed.

Getting each application to switch#

$IRIX_MODE only changes what the four live CLIs render on the spot. Every deployed artifact is a static file, so an application that isn’t one of those four CLIs needs its own nudge — some via a config line, some via native in-app switching. None of this is automated by irix itself; the target engine’s job ends at “both files exist on disk.”

  • kitty — no built-in light switch. irix deploy kitty writes kitty.conf (the file kitty loads) and kitty-light.conf side by side, but nothing points from one to the other. If you want an easy toggle rather than re-deploying, restructure your kitty.conf around kitty’s own include directive instead of letting irix deploy own the whole file:

    # kitty.conf
    include current-theme.conf
    

    then symlink current-theme.conf at whichever of kitty.conf’s rendered content (copied aside, since irix deploy still wants to write the real kitty.conf) or kitty-light.conf you want live, and reload with kitty @ load-config or ctrl+shift+F5.

  • vim — out/editors/irix.vim is the dual-mode-single-artifact case: one file, both halves. :colorscheme irix picks it up once; after that, plain vim’s own :set background=dark / :set background=light selects the half — no second file, no redeploy.

  • sublime — deployed as two separate files, irix-dark.sublime-color-scheme and irix-light.sublime-color-scheme, both landing in Packages/User/. Switch via Preferences → Color Scheme → Irix Dark (or Irix Light) — Sublime’s own scheme picker, no config file to hand-edit.

  • vscode — same shape as sublime: two independent theme files, no automatic pairing. Switch via VS Code’s own Preferences: Color Theme picker (Ctrl+K Ctrl+T) once both are installed as described in Editors.

  • lsd — colors.yaml and colors-light.yaml deploy side by side, but lsd only ever reads the file literally named colors.yaml. Switching means overwriting that name — e.g. cp colors-light.yaml colors.yaml inside $XDG_CONFIG_HOME/lsd/ — there’s no lsd config key to point at an alternate filename.

  • cssvars — the other single-artifact case: :root holds the light values, a .dark class block overrides them. Toggle by adding/removing the dark class on <html> or <body>, no file swap at all.

  • Everything else generate-only (starship, delta, fzf, zshcolors, dircolors, the gpl/slack/ gsheets/pymodule targets, …) is a plain two-file pair with no shared switch — you re-source or re-paste whichever mode’s file you want active. How to Deploy Each Target has the exact destination and activation line for each.

The legibility guarantee#

Per-mode isn’t just “same addresses, different palette lookup” everywhere. A handful of semantics.yaml/anchors/*.yaml roles carry a {dark: ..., light: ...} override instead of one shared address, because Radix’s sign1/sign2 rung — calibrated for a dark surface — falls below the WCAG AA contrast floor against a light background for a few roles (accent, keyword, comment, and others). Dark addresses are untouched; only the light half of those roles moved one or two rungs deeper on the same hue until it cleared the floor.

tests/test_legibility.py is the enforcement side of that fix — a frozen ledger of every text-ish role’s measured contrast, in both modes, that fails loudly on any drift in either direction. The full rationale, the before/after contrast numbers, and how the ledger works are in the architecture reference; this page only needs you to know the guarantee exists — every light artifact is legible by measurement, not by eye.