v0.2.78 cc6b04d

SKILL.md RawHistoryFolder


name: write-zot-themes description: Help the user create, install, or package zot themes, including theme-only extensions.

Writing zot themes

Use this skill when the user asks for help creating, editing, installing, debugging, or packaging a zot color theme. Read this skill before generating a theme file or advising on theme extension layout.

What a zot theme is

A zot theme is a JSON file that overrides any subset of zot's built-in light/dark theme values. Theme files are intentionally permissive: nothing is required. A file may contain only colors, only spinner settings, only syntax colors, or only metadata. Missing values always inherit from the built-in detected light/dark default.

User themes are discovered from:

$ZOT_HOME/themes/*.json

Extension themes are discovered in-place from loaded extension dirs:

$ZOT_HOME/extensions/<extension>/theme.json
$ZOT_HOME/extensions/<extension>/themes/theme.json
<project>/.zot/extensions/<extension>/theme.json
<project>/.zot/extensions/<extension>/themes/theme.json

zot does not copy extension themes into $ZOT_HOME/themes; extension owned themes stay in the extension directory. The settings picker stores an absolute path for extension-owned themes and loads that file directly.

Minimal examples

Empty / metadata-only theme

Valid; inherits all colors/spinner/syntax from zot defaults.

{
  "name": "my-theme",
  "description": "Metadata only; all visuals inherit zot defaults."
}

Change one color for both light and dark

{
  "name": "pink-accent",
  "colors": {
    "accent": 204
  }
}

Change one color per mode

{
  "name": "split-accent",
  "colors": {
    "dark": { "accent": 204 },
    "light": { "accent": 161 }
  }
}

Spinner-only theme

Top-level spinner overrides are valid and apply to both modes.

{
  "name": "custom-spinner",
  "description": "Only changes the busy spinner.",
  "spinner_frames": ["◢", "◣", "◤", "◥"],
  "spinner_messages": ["working"],
  "spinner_interval_ms": 120
}

Dark-only theme also works in light terminals

If colors.light is missing, zot applies colors.dark overrides on top of the built-in light default when running in light mode. The inverse is also true: if dark is missing but light exists, light settings are used on dark defaults.

{
  "name": "custom-spinner",
  "description": "An alternative spinner for zot that only displays a single spinner text.",
  "colors": {
    "dark": {
      "spinner_frames": ["◢", "◣", "◤", "◥"],
      "spinner_messages": ["working"],
      "spinner_interval_ms": 120
    }
  }
}

Full theme shape

All fields below are optional.

{
  "name": "my-theme",
  "description": "Shown in /settings → color theme.",
  "color_descriptions": {
    "accent": "Optional documentation for humans. zot ignores this object."
  },
  "colors": {
    "dark": {
      "fg": 253,
      "muted": 244,
      "accent": 111,
      "user": 180,
      "user_bubble_bg": "#42454b",
      "user_bubble_fg": 248,
      "assistant": 117,
      "tool": 114,
      "tool_out": 245,
      "error": 203,
      "warning": 214,
      "spinner": 183,
      "selection_bg": 24,
      "selection_fg": 231,
      "spinner_frames": ["⠋", "⠙", "⠚", "⠞", "⠖", "⠦", "⠴", "⠲", "⠳", "⠓"],
      "spinner_messages": ["thinking", "working"],
      "spinner_interval_ms": 80,
      "syntax_base_style": "monokai",
      "syntax": {
        "keyword": "#81a1c1 bold",
        "keyword_constant": "#81a1c1",
        "keyword_declaration": "#81a1c1",
        "keyword_namespace": "#81a1c1",
        "keyword_reserved": "#81a1c1 bold",
        "keyword_type": "#88c0d0",
        "name_builtin": "#88c0d0",
        "name_function": "#8fbcbb",
        "name_class": "#a3be8c bold",
        "name_decorator": "#b48ead",
        "literal_string": "#a3be8c",
        "literal_string_escape": "#bf616a",
        "literal_number": "#d08770",
        "comment": "#616e88 italic",
        "comment_preproc": "#b48ead",
        "operator": "#eceff4",
        "punctuation": "#d8dee9",
        "text": "#e5e9f0"
      }
    },
    "light": {
      "fg": 236,
      "muted": 244,
      "accent": 33
    }
  }
}

You may also put overrides directly at the top level, or directly under colors, when they should apply to both modes:

{
  "name": "tiny",
  "accent": 204,
  "colors": {
    "spinner_messages": ["shipping"]
  }
}

Color fields

  • fg — default foreground text.
  • muted — secondary text, dividers, gutters, inactive hints.
  • accent — prompt bar, bullets, links, headings, active markers.
  • user — user role label color; mostly compatibility.
  • user_bubble_bg — background behind user message rows.
  • user_bubble_fg — foreground inside user message rows.
  • assistant — assistant/zot accent and spinner text.
  • tool — tool names, success marks, diff additions.
  • tool_out — plain tool-output text.
  • error — errors, refused calls, diff deletions.
  • warning — warnings and high context-usage state.
  • spinner — reserved spinner color slot.
  • selection_bg — highlighted row background.
  • selection_fg — highlighted row foreground.

Most color fields are xterm-256 indexes (0–255).

user_bubble_bg supports richer terminal color forms:

254
"#42454b"
{ "mode": "256", "index": 254 }
{ "mode": "ansi", "index": 100 }
{ "mode": "rgb", "r": 66, "g": 69, "b": 75 }

Spinner fields

Spinner settings can appear at top level, under colors, or under colors.dark / colors.light.

  • spinner_frames — list of frame strings. Use single-cell glyphs when possible so status-bar alignment stays clean.
  • spinner_messages — list of messages; zot chooses one per turn.
  • spinner_interval_ms — frame interval in milliseconds; must be positive. Missing/invalid falls back to 80ms.

Example:

{
  "spinner_frames": ["◐", "◓", "◑", "◒"],
  "spinner_messages": ["shipping pixels", "warming edge cache"],
  "spinner_interval_ms": 120
}

Syntax fields

Syntax highlighting uses Chroma style entries. Values may include attributes after the color, such as bold, italic, or underline.

Common fields:

  • keyword
  • keyword_constant
  • keyword_declaration
  • keyword_namespace
  • keyword_reserved
  • keyword_type
  • name_builtin
  • name_function
  • name_class
  • name_decorator
  • literal_string
  • literal_string_escape
  • literal_number
  • comment
  • comment_preproc
  • operator
  • punctuation
  • text

Example:

{
  "colors": {
    "dark": {
      "syntax_base_style": "monokai",
      "syntax": {
        "keyword": "#f05b8d",
        "name_function": "#b675f1",
        "literal_string": "#58c760",
        "comment": "#a1a1a1 italic"
      }
    }
  }
}

Installing a user theme

mkdir -p "$ZOT_HOME/themes"
cp my-theme.json "$ZOT_HOME/themes/my-theme.json"

Then open /settings and choose color theme. zot switches theme immediately and persists the selection in $ZOT_HOME/config.json.

If a selected theme file is deleted, zot resets the setting to the built-in auto/default theme.

Theme-only extensions

A zot extension can exist only to ship a theme. No slash command, subprocess, or executable is required when the extension contains a valid theme file.

Layout:

$ZOT_HOME/extensions/my-theme-extension/
├── extension.json
└── theme.json

or:

$ZOT_HOME/extensions/my-theme-extension/
├── extension.json
└── themes/
    └── theme.json

extension.json for a theme-only extension:

{
  "name": "my-theme-extension",
  "version": "1.0.0",
  "description": "Ships a zot color theme",
  "enabled": true
}

No exec is needed when theme.json or themes/theme.json exists. If exec is present, zot treats it as a normal extension too.

In /settings → color theme, extension themes show source info in the description, e.g. from extension my-theme-extension — ....

Recommendations

  • Prefer short descriptions; settings wraps them, but concise is easier to scan.
  • Keep spinner frames single-width when possible.
  • For theme packages, use a unique extension name so the source label is clear.
  • For user-editable themes, keep comments out of JSON; JSON comments are not supported.
  • Validate with python3 -m json.tool theme.json before installing.
source
1---
2name: write-zot-themes
3description: Help the user create, install, or package zot themes, including theme-only extensions.
4---
5
6# Writing zot themes
7
8Use this skill when the user asks for help creating, editing,
9installing, debugging, or packaging a zot color theme. Read this skill
10before generating a theme file or advising on theme extension layout.
11
12## What a zot theme is
13
14A zot theme is a JSON file that overrides any subset of zot's built-in
15light/dark theme values. Theme files are intentionally permissive:
16nothing is required. A file may contain only colors, only spinner
17settings, only syntax colors, or only metadata. Missing values always
18inherit from the built-in detected light/dark default.
19
20User themes are discovered from:
21
22```text
23$ZOT_HOME/themes/*.json
24```
25
26Extension themes are discovered in-place from loaded extension dirs:
27
28```text
29$ZOT_HOME/extensions/<extension>/theme.json
30$ZOT_HOME/extensions/<extension>/themes/theme.json
31<project>/.zot/extensions/<extension>/theme.json
32<project>/.zot/extensions/<extension>/themes/theme.json
33```
34
35zot does **not** copy extension themes into `$ZOT_HOME/themes`; extension
36owned themes stay in the extension directory. The settings picker stores
37an absolute path for extension-owned themes and loads that file directly.
38
39## Minimal examples
40
41### Empty / metadata-only theme
42
43Valid; inherits all colors/spinner/syntax from zot defaults.
44
45```json
46{
47  "name": "my-theme",
48  "description": "Metadata only; all visuals inherit zot defaults."
49}
50```
51
52### Change one color for both light and dark
53
54```json
55{
56  "name": "pink-accent",
57  "colors": {
58    "accent": 204
59  }
60}
61```
62
63### Change one color per mode
64
65```json
66{
67  "name": "split-accent",
68  "colors": {
69    "dark": { "accent": 204 },
70    "light": { "accent": 161 }
71  }
72}
73```
74
75### Spinner-only theme
76
77Top-level spinner overrides are valid and apply to both modes.
78
79```json
80{
81  "name": "custom-spinner",
82  "description": "Only changes the busy spinner.",
83  "spinner_frames": ["◢", "◣", "◤", "◥"],
84  "spinner_messages": ["working"],
85  "spinner_interval_ms": 120
86}
87```
88
89### Dark-only theme also works in light terminals
90
91If `colors.light` is missing, zot applies `colors.dark` overrides on
92top of the built-in light default when running in light mode. The
93inverse is also true: if dark is missing but light exists, light
94settings are used on dark defaults.
95
96```json
97{
98  "name": "custom-spinner",
99  "description": "An alternative spinner for zot that only displays a single spinner text.",
100  "colors": {
101    "dark": {
102      "spinner_frames": ["◢", "◣", "◤", "◥"],
103      "spinner_messages": ["working"],
104      "spinner_interval_ms": 120
105    }
106  }
107}
108```
109
110## Full theme shape
111
112All fields below are optional.
113
114```json
115{
116  "name": "my-theme",
117  "description": "Shown in /settings → color theme.",
118  "color_descriptions": {
119    "accent": "Optional documentation for humans. zot ignores this object."
120  },
121  "colors": {
122    "dark": {
123      "fg": 253,
124      "muted": 244,
125      "accent": 111,
126      "user": 180,
127      "user_bubble_bg": "#42454b",
128      "user_bubble_fg": 248,
129      "assistant": 117,
130      "tool": 114,
131      "tool_out": 245,
132      "error": 203,
133      "warning": 214,
134      "spinner": 183,
135      "selection_bg": 24,
136      "selection_fg": 231,
137      "spinner_frames": ["⠋", "⠙", "⠚", "⠞", "⠖", "⠦", "⠴", "⠲", "⠳", "⠓"],
138      "spinner_messages": ["thinking", "working"],
139      "spinner_interval_ms": 80,
140      "syntax_base_style": "monokai",
141      "syntax": {
142        "keyword": "#81a1c1 bold",
143        "keyword_constant": "#81a1c1",
144        "keyword_declaration": "#81a1c1",
145        "keyword_namespace": "#81a1c1",
146        "keyword_reserved": "#81a1c1 bold",
147        "keyword_type": "#88c0d0",
148        "name_builtin": "#88c0d0",
149        "name_function": "#8fbcbb",
150        "name_class": "#a3be8c bold",
151        "name_decorator": "#b48ead",
152        "literal_string": "#a3be8c",
153        "literal_string_escape": "#bf616a",
154        "literal_number": "#d08770",
155        "comment": "#616e88 italic",
156        "comment_preproc": "#b48ead",
157        "operator": "#eceff4",
158        "punctuation": "#d8dee9",
159        "text": "#e5e9f0"
160      }
161    },
162    "light": {
163      "fg": 236,
164      "muted": 244,
165      "accent": 33
166    }
167  }
168}
169```
170
171You may also put overrides directly at the top level, or directly
172under `colors`, when they should apply to both modes:
173
174```json
175{
176  "name": "tiny",
177  "accent": 204,
178  "colors": {
179    "spinner_messages": ["shipping"]
180  }
181}
182```
183
184## Color fields
185
186- `fg` — default foreground text.
187- `muted` — secondary text, dividers, gutters, inactive hints.
188- `accent` — prompt bar, bullets, links, headings, active markers.
189- `user` — user role label color; mostly compatibility.
190- `user_bubble_bg` — background behind user message rows.
191- `user_bubble_fg` — foreground inside user message rows.
192- `assistant` — assistant/zot accent and spinner text.
193- `tool` — tool names, success marks, diff additions.
194- `tool_out` — plain tool-output text.
195- `error` — errors, refused calls, diff deletions.
196- `warning` — warnings and high context-usage state.
197- `spinner` — reserved spinner color slot.
198- `selection_bg` — highlighted row background.
199- `selection_fg` — highlighted row foreground.
200
201Most color fields are xterm-256 indexes (`0`–`255`).
202
203`user_bubble_bg` supports richer terminal color forms:
204
205```json
206254
207"#42454b"
208{ "mode": "256", "index": 254 }
209{ "mode": "ansi", "index": 100 }
210{ "mode": "rgb", "r": 66, "g": 69, "b": 75 }
211```
212
213## Spinner fields
214
215Spinner settings can appear at top level, under `colors`, or under
216`colors.dark` / `colors.light`.
217
218- `spinner_frames` — list of frame strings. Use single-cell glyphs
219  when possible so status-bar alignment stays clean.
220- `spinner_messages` — list of messages; zot chooses one per turn.
221- `spinner_interval_ms` — frame interval in milliseconds; must be
222  positive. Missing/invalid falls back to 80ms.
223
224Example:
225
226```json
227{
228  "spinner_frames": ["◐", "◓", "◑", "◒"],
229  "spinner_messages": ["shipping pixels", "warming edge cache"],
230  "spinner_interval_ms": 120
231}
232```
233
234## Syntax fields
235
236Syntax highlighting uses Chroma style entries. Values may include
237attributes after the color, such as `bold`, `italic`, or `underline`.
238
239Common fields:
240
241- `keyword`
242- `keyword_constant`
243- `keyword_declaration`
244- `keyword_namespace`
245- `keyword_reserved`
246- `keyword_type`
247- `name_builtin`
248- `name_function`
249- `name_class`
250- `name_decorator`
251- `literal_string`
252- `literal_string_escape`
253- `literal_number`
254- `comment`
255- `comment_preproc`
256- `operator`
257- `punctuation`
258- `text`
259
260Example:
261
262```json
263{
264  "colors": {
265    "dark": {
266      "syntax_base_style": "monokai",
267      "syntax": {
268        "keyword": "#f05b8d",
269        "name_function": "#b675f1",
270        "literal_string": "#58c760",
271        "comment": "#a1a1a1 italic"
272      }
273    }
274  }
275}
276```
277
278## Installing a user theme
279
280```bash
281mkdir -p "$ZOT_HOME/themes"
282cp my-theme.json "$ZOT_HOME/themes/my-theme.json"
283```
284
285Then open `/settings` and choose **color theme**. zot switches theme
286immediately and persists the selection in `$ZOT_HOME/config.json`.
287
288If a selected theme file is deleted, zot resets the setting to the
289built-in auto/default theme.
290
291## Theme-only extensions
292
293A zot extension can exist only to ship a theme. No slash command,
294subprocess, or executable is required when the extension contains a
295valid theme file.
296
297Layout:
298
299```text
300$ZOT_HOME/extensions/my-theme-extension/
301├── extension.json
302└── theme.json
303```
304
305or:
306
307```text
308$ZOT_HOME/extensions/my-theme-extension/
309├── extension.json
310└── themes/
311    └── theme.json
312```
313
314`extension.json` for a theme-only extension:
315
316```json
317{
318  "name": "my-theme-extension",
319  "version": "1.0.0",
320  "description": "Ships a zot color theme",
321  "enabled": true
322}
323```
324
325No `exec` is needed when `theme.json` or `themes/theme.json` exists.
326If `exec` is present, zot treats it as a normal extension too.
327
328In `/settings → color theme`, extension themes show source info in
329the description, e.g. `from extension my-theme-extension — ...`.
330
331## Recommendations
332
333- Prefer short descriptions; settings wraps them, but concise is
334  easier to scan.
335- Keep spinner frames single-width when possible.
336- For theme packages, use a unique extension name so the source label
337  is clear.
338- For user-editable themes, keep comments out of JSON; JSON comments
339  are not supported.
340- Validate with `python3 -m json.tool theme.json` before installing.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 477

↑↓ moveenter openesc close