ADR 0013: Themes are bounded semantic palettes in Lua configuration
Canonical Quirl project documentation synced from docs/decisions/0013-lua-config-themes.md.
Context
Quirl's rich and simple terminal surfaces used separate hard-coded color choices. That made a theme change inconsistent across the prompt, syntax highlighting, diagnostics, completion chrome, and status line. It also left no typed way for users to add a palette through the existing Lua configuration system.
Theme input is untrusted configuration. Names, retained strings, and the number
of palettes must be bounded. Theme evaluation must never run a Lua callback on
the per-keystroke or paint path, and NO_COLOR must remain authoritative.
Decision
Configuration schema v3 adds ui.theme and ui.themes. ui.theme selects a
built-in or configured palette and defaults to tokyo-night. Quirl ships 30
popular dark palettes curated from the maintained
Gogh terminal-theme catalog, plus ansi as
a conservative compatibility alternative. ui.themes is a Lua table of
immutable semantic palettes; it is evaluated once with the rest of config.lua,
deserialized into deny-unknown Rust structures, validated, and then passed to
both terminal surfaces as ordinary data.
Each palette supplies a fixed set of semantic roles. Quirl owns style
modifiers, selection behavior, layout, and terminal cleanup. Palette names are
safe ASCII identifiers of at most 64 bytes, at most 32 custom palettes are
retained, and every color is exactly #RRGGBB. Custom palettes may not shadow
built-ins. Unknown selections, malformed names, missing or unknown roles, and
invalid colors reject the complete configuration. Count and retained-string
overflows return ErrorCode::ResourceLimit with the observed and configured
limits.
The resolved palette is copied into the editor at a safe prompt boundary. No
Lua code runs while rendering. When styling is disabled by NO_COLOR, a dumb
terminal, or a non-TTY, foreground and background colors are both suppressed
while textual labels and safe modifiers remain.
Legacy v0, v1, and v2 configurations migrate deterministically to v3 defaults.
Future versions fail closed. The crate boundary remains unchanged:
quirl-lua owns the schema, validation, built-ins, and migration;
quirl-ui maps semantic roles to backend styles; quirl-cli composes the
active config.
Consequences
- Tokyo Night is coherent across the Ratatui and Reedline surfaces by default.
- Thirty built-in palettes cover widely used editor and terminal theme families without adding render-time lookup or third-party dependencies.
- Users can add computed themes using the same bounded Lua configuration that already owns prompt and UI settings.
- Themes cannot execute paint-time code, emit terminal controls, grow without an explicit bound, or replace Quirl-owned layout and modifiers.
- The config protocol advances to v3 and its generated SDK, migration evidence, examples, configuration views, and freeze manifest must change together.
ADR 0012: Ratatui is the default capable-terminal surface
Canonical Quirl project documentation synced from docs/decisions/0012-ratatui-interactive-surface.md.
ADR 0014: External history tools integrate through a bounded provider boundary
Canonical Quirl project documentation synced from docs/decisions/0014-external-history-provider-boundary.md.