zut themes
zut uses the controlling terminal as the source of truth for its default
appearance. Theme files are JSON overlays: every field is optional.
Built-in choices
Open /settings and select color theme.
- auto (default) follows the terminal default foreground and background,
ANSI palette, color depth, and reported light/dark scheme. It does not paint
a full-row background or set a cursor color.
- dark and light use zut's fixed palettes. They remain fixed when the
terminal appearance changes.
- A custom theme overlays
auto. Unspecified roles remain terminal-owned;
explicit JSON values remain literal overrides.
inherited is no longer a theme choice. A persisted inherited value resets
to auto.
ZUT_THEME=dark or ZUT_THEME=light forces that choice for one process. The
settings dialog still saves the next-launch preference, but cannot override the
environment for the running process. An unset ZUT_THEME or ZUT_THEME=auto
uses the saved preference.
Live terminal changes
Interactive zut queries terminal defaults and ANSI slots at startup. When the
terminal supports DEC mode 2031 color-scheme notifications, zut follows
reported scheme changes and refreshes its terminal profile. It probes the mode
before changing it and disables it on exit only when zut enabled a known-reset
mode itself. Terminals without notification support receive a low-rate OSC 11
and scheme query fallback (about two seconds).
Terminal support varies through multiplexers and remote sessions. If a reply
does not arrive, zut remains usable with terminal default SGR colors and ANSI
slots. Existing scrollback is never recolored or cleared by a theme change;
only the visible live frame is repainted.
Theme files and reload
User themes live under:
$ZUT_HOME/themes/*.json
Extension-owned themes are loaded in place from:
$ZUT_HOME/extensions/<extension>/theme.json
$ZUT_HOME/extensions/<extension>/themes/theme.json
<project>/.zut/extensions/<extension>/theme.json
<project>/.zut/extensions/<extension>/themes/theme.json
An active custom file is polled every 500 ms. A valid complete edit applies
without restarting zut. Invalid JSON, invalid colors, unsupported syntax
styles, and oversized files leave the last valid revision active. Brief atomic
rename gaps are tolerated; a file that stays missing resets the saved choice to
auto and shows a status message.
Minimal files
{
"name": "pink-accent",
"colors": { "accent": 204 }
}
Shared overrides can appear at the top level or directly in colors.
Mode-specific overrides go under colors.dark and colors.light; zut uses a
reported color scheme when available, and a background-luminance fallback
otherwise.
{
"name": "split-accent",
"colors": {
"dark": { "accent": 204 },
"light": { "accent": 161 }
}
}
{
"name": "spinner-only",
"spinner_frames": ["◢", "◣", "◤", "◥"],
"spinner_interval_ms": 120
}
Color values
Every semantic color accepts one of:
254
"#42454b"
{ "mode": "256", "index": 254 }
{ "mode": "ansi", "index": 100 }
{ "mode": "rgb", "r": 66, "g": 69, "b": 75 }
Numeric values are literal xterm-256 indexes. ANSI values are literal ANSI SGR
colors. RGB values use truecolor when available, otherwise zut quantizes them
to the active terminal capability. auto-generated colors are distinct:
they retain terminal-default or terminal-palette-slot provenance and therefore
change with the terminal palette.
Color roles are fg, muted, accent, background, user,
user_bubble_bg, user_bubble_fg, assistant, tool, tool_out, error,
warning, spinner, thinking_max (or thinkingMax), selection_bg, and
selection_fg. background intentionally paints the full zut row; omit it
to retain terminal background ownership.
spinner_frames contains 1–64 non-empty frames. spinner_interval_ms must be
between 10 and 10000. Theme files are limited to 1 MiB.
Syntax
Custom syntax entries use Chroma style entries, for example:
{
"colors": {
"dark": {
"syntax": {
"keyword": "#f05b8d bold",
"literal_string": "#58c760",
"comment": "#a1a1a1 italic"
}
}
}
}
In auto, zut keeps Chroma for lexing but emits its own exact terminal SGR
sequences. Keywords, names, strings, errors, numbers, comments, and plain text
therefore retain terminal ANSI-slot identity instead of being remapped through
the xterm color cube.
source
1# zut themes
2
3zut uses the controlling terminal as the source of truth for its default
4appearance. Theme files are JSON overlays: every field is optional.
5
6## Built-in choices
7
8Open `/settings` and select **color theme**.
9
10- **auto** (default) follows the terminal default foreground and background,
11 ANSI palette, color depth, and reported light/dark scheme. It does not paint
12 a full-row background or set a cursor color.
13- **dark** and **light** use zut's fixed palettes. They remain fixed when the
14 terminal appearance changes.
15- A **custom theme** overlays `auto`. Unspecified roles remain terminal-owned;
16 explicit JSON values remain literal overrides.
17
18`inherited` is no longer a theme choice. A persisted `inherited` value resets
19to `auto`.
20
21`ZUT_THEME=dark` or `ZUT_THEME=light` forces that choice for one process. The
22settings dialog still saves the next-launch preference, but cannot override the
23environment for the running process. An unset `ZUT_THEME` or `ZUT_THEME=auto`
24uses the saved preference.
25
26## Live terminal changes
27
28Interactive zut queries terminal defaults and ANSI slots at startup. When the
29terminal supports DEC mode 2031 color-scheme notifications, zut follows
30reported scheme changes and refreshes its terminal profile. It probes the mode
31before changing it and disables it on exit only when zut enabled a known-reset
32mode itself. Terminals without notification support receive a low-rate OSC 11
33and scheme query fallback (about two seconds).
34
35Terminal support varies through multiplexers and remote sessions. If a reply
36does not arrive, zut remains usable with terminal default SGR colors and ANSI
37slots. Existing scrollback is never recolored or cleared by a theme change;
38only the visible live frame is repainted.
39
40## Theme files and reload
41
42User themes live under:
43
44```text
45$ZUT_HOME/themes/*.json
46```
47
48Extension-owned themes are loaded in place from:
49
50```text
51$ZUT_HOME/extensions/<extension>/theme.json
52$ZUT_HOME/extensions/<extension>/themes/theme.json
53<project>/.zut/extensions/<extension>/theme.json
54<project>/.zut/extensions/<extension>/themes/theme.json
55```
56
57An active custom file is polled every 500 ms. A valid complete edit applies
58without restarting zut. Invalid JSON, invalid colors, unsupported syntax
59styles, and oversized files leave the last valid revision active. Brief atomic
60rename gaps are tolerated; a file that stays missing resets the saved choice to
61`auto` and shows a status message.
62
63## Minimal files
64
65```json
66{
67 "name": "pink-accent",
68 "colors": { "accent": 204 }
69}
70```
71
72Shared overrides can appear at the top level or directly in `colors`.
73Mode-specific overrides go under `colors.dark` and `colors.light`; zut uses a
74reported color scheme when available, and a background-luminance fallback
75otherwise.
76
77```json
78{
79 "name": "split-accent",
80 "colors": {
81 "dark": { "accent": 204 },
82 "light": { "accent": 161 }
83 }
84}
85```
86
87```json
88{
89 "name": "spinner-only",
90 "spinner_frames": ["◢", "◣", "◤", "◥"],
91 "spinner_interval_ms": 120
92}
93```
94
95## Color values
96
97Every semantic color accepts one of:
98
99```json
100254
101"#42454b"
102{ "mode": "256", "index": 254 }
103{ "mode": "ansi", "index": 100 }
104{ "mode": "rgb", "r": 66, "g": 69, "b": 75 }
105```
106
107Numeric values are literal xterm-256 indexes. ANSI values are literal ANSI SGR
108colors. RGB values use truecolor when available, otherwise zut quantizes them
109to the active terminal capability. `auto`-generated colors are distinct:
110they retain terminal-default or terminal-palette-slot provenance and therefore
111change with the terminal palette.
112
113Color roles are `fg`, `muted`, `accent`, `background`, `user`,
114`user_bubble_bg`, `user_bubble_fg`, `assistant`, `tool`, `tool_out`, `error`,
115`warning`, `spinner`, `thinking_max` (or `thinkingMax`), `selection_bg`, and
116`selection_fg`. `background` intentionally paints the full zut row; omit it
117to retain terminal background ownership.
118
119`spinner_frames` contains 1–64 non-empty frames. `spinner_interval_ms` must be
120between 10 and 10000. Theme files are limited to 1 MiB.
121
122## Syntax
123
124Custom `syntax` entries use Chroma style entries, for example:
125
126```json
127{
128 "colors": {
129 "dark": {
130 "syntax": {
131 "keyword": "#f05b8d bold",
132 "literal_string": "#58c760",
133 "comment": "#a1a1a1 italic"
134 }
135 }
136 }
137}
138```
139
140In `auto`, zut keeps Chroma for lexing but emits its own exact terminal SGR
141sequences. Keywords, names, strings, errors, numbers, comments, and plain text
142therefore retain terminal ANSI-slot identity instead of being remapped through
143the xterm color cube.