Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Themes

The TUI is colored by semantic roles, not raw hexes. Every render site resolves a role (accent, text_primary, selection_bg, …) through the active theme, so one switch restyles the whole interface at runtime. A theme is one file, 43 keys, done.

Switching themes

КомандаWhat it does
/themeOpens the interactive picker: ↑/↓ (or j/k) move the cursor and preview live, the whole UI recolors under the arrow keys. Enter applies and persists, Esc (or q) cancels and reverts to whatever was active when the picker opened.
/theme listLists built-in themes and user presets, then re-scans ~/.opencrabs/themes/. Files that fail validation are listed with a human-readable rejection reason, never silently ignored.
/theme set <name>Applies a theme immediately and writes it to your config. Lookup is case-insensitive across built-ins and user presets; an unknown name tells you to run /theme list.
/theme resetReturns to the default (crab-dark) and clears the config key.

To pin a theme without the picker, set it in config.toml:

[tui]
theme = "nord"

The value is applied at boot before the first frame. An empty or unknown name falls back to crab-dark. User theme files are re-scanned on every /theme invocation, so editing a preset file hot-loads it without restarting the TUI.

Built-in themes

There are 39 built-in themes: 8 hand-tuned presets plus a curated pack of 31 converted from popular upstream palettes (see Imported themes). crab-dark is the default and matches the historical OpenCrabs look.

PresetVibe
crab-darkThe house palette: burnt-orange accent, cool grays, deep ink
draculaThe classic purple-blue dark theme with orange accent
alucardWarm dark, muted contrast (Castlevania’s good-boy Dracula)
monokaiSublime’s iconic warm dark with pink/yellow
catppuccin-mochaPastel dark, soft and low-contrast
catppuccin-latteThe same pastels on light surfaces
solarized-lightEthan Schoonlif’s light base
solarized-darkThe original dark base

The curated pack adds: aura, ayu, carbonfox, catppuccin-frappe, catppuccin-macchiato, cobalt2, cursor, everforest, flexoki, github, gruvbox, gruvbox-light, kanagawa, material, matrix, mercury, nightowl, nord, one-dark, opencode, orng, osaka-jade, palenight, rosepine, rosepine-dawn, synthwave84, tokyonight, tokyonight-storm, vercel, vesper, zenburn.

Swatches show four anchor roles per theme (accent, body text, success, ink background), read from the shipped sources. Regenerate with python3 docs/scripts/gen_theme_gallery.py.

ThemeTypeaccenttextsuccessinkИсточник
crab-darkdefault #d76414 #c8c8d2 #50c878 #14141ebuilt-in
draculahand-built #ffb86c #f8f8f2 #50fa7b #282a36built-in
alucardhand-built #a34d14 #1f1f1f #14710a #1f1f1fbuilt-in
monokaihand-built #fd971f #f8f8f2 #a6e22e #272822built-in
catppuccin-mochahand-built #fab387 #cdd6f4 #a6e3a1 #1e1e2ebuilt-in
catppuccin-lattehand-built #fe640b #4c4f69 #40a02b #4c4f69built-in
solarized-lighthand-built #cb4b16 #657b83 #859900 #073642built-in
solarized-darkhand-built #cb4b16 #839496 #859900 #002b36built-in
auracurated pack #a277ff #edecee #61ffca #0f0f0fopencode, dark, 2026-09-11
ayucurated pack #e6b450 #bfbdb6 #7fd962 #0b0e14opencode, dark, 2026-09-11
carbonfoxcurated pack #ff7eb6 #f2f4f8 #25be6a #161616opencode, dark, 2026-09-11
catppuccin-macchiatocurated pack #f5bde6 #cad3f5 #a6da95 #24273aopencode, dark, 2026-09-11
cobalt2curated pack #2affdf #ffffff #9eff80 #193549opencode, dark, 2026-09-11
cursorcurated pack #88c0d0 #e4e4e4 #3fa266 #181818opencode, dark, 2026-09-11
everforestcurated pack #d699b6 #d3c6aa #a7c080 #2d353bopencode, dark, 2026-09-11
flexokicurated pack #8b7ec8 #cecdc3 #879a39 #100f0fopencode, dark, 2026-09-11
githubcurated pack #39c5cf #c9d1d9 #3fb950 #0d1117opencode, dark, 2026-09-11
gruvboxcurated pack #8ec07c #ebdbb2 #b8bb26 #282828opencode, dark, 2026-09-11
kanagawacurated pack #d27e99 #dcd7ba #98bb6c #1f1f28opencode, dark, 2026-09-11
materialcurated pack #89ddff #eeffff #c3e88d #263238opencode, dark, 2026-09-11
matrixcurated pack #c770ff #62ff94 #62ff94 #0a0e0aopencode, dark, 2026-09-11
mercurycurated pack #8da4f5 #dddde5 #77c599 #171721opencode, dark, 2026-09-11
nightowlcurated pack #c792ea #d6deeb #c5e478 #011627opencode, dark, 2026-09-11
nordcurated pack #8fbcbb #eceff4 #a3be8c #2e3440opencode, dark, 2026-09-11
one-darkcurated pack #56b6c2 #abb2bf #98c379 #282c34opencode, dark, 2026-09-11
opencodecurated pack #9d7cd8 #eeeeee #7fd88f #0a0a0aopencode, dark, 2026-09-11
orngcurated pack #fff7f1 #eeeeee #6ba1e6 #0a0a0aopencode, dark, 2026-09-11
osaka-jadecurated pack #549e6a #c1c497 #549e6a #111c18opencode, dark, 2026-09-11
palenightcurated pack #89ddff #a6accd #c3e88d #292d3eopencode, dark, 2026-09-11
rosepinecurated pack #ebbcba #e0def4 #31748f #191724opencode, dark, 2026-09-11
synthwave84curated pack #b084eb #ffffff #72f1b8 #262335opencode, dark, 2026-09-11
tokyonightcurated pack #ff966c #c8d3f5 #c3e88d #1a1b26opencode, dark, 2026-09-11
vercelcurated pack #8e4ec6 #ededed #46a758 #000000opencode, dark, 2026-09-11
vespercurated pack #ffc799 #ffffff #99ffe4 #101010opencode, dark, 2026-09-11
zenburncurated pack #93e0e3 #dcdccc #7f9f7f #3f3f3fopencode, dark, 2026-09-11
catppuccin-frappecurated pack #e5c890 #c6d0f5 #a6d189 #303446alacritty-theme, 2026-09-11
gruvbox-lightcurated pack #b57614 #3c3836 #98971a #fbf1c7alacritty-theme, 2026-09-11
rosepine-dawncurated pack #d38d2f #575279 #286983 #faf4edalacritty-theme, 2026-09-11
tokyonight-stormcurated pack #ff9e64 #a9b1d6 #9ece6a #24283balacritty-theme, 2026-09-11

The 43 roles

A user theme is a flat TOML file mapping every role to a #RRGGBB hex. Role names double as the TOML keys. What each one colors:

GroupКлавишаColors
AccentsaccentPrimary emphasis: prompts, active states, the crab orange
accent_tealPrimary action / selected accent
accent_softPassive, informational accent (soft white)
Texttext_primaryBody text
text_secondarySecondary text
text_mutedMuted labels
text_dimDeepest text tier
Chrome graysgrayBorders, passive labels, info lines (the workhorse)
gray_midSecondary borders, quiet panel text
gray_detailDetail rows under primary rows (tool list)
gray_dimInactive borders (unfocused input frame)
gray_darkDeeper inactive chrome
gray_baseDarkest neutral foreground (plan-widget borders)
gray_lightBright neutral text
gray_softSoft label text
gray_mutedMuted body text (plan widget)
Positivesuccess“ok” states, active pane borders
analytics_greenMission-control bars and values
green_checkChecked-markdown checkboxes
NegativeerrorPrimary failures
error_softError titles
error_fadedError bodies
WarningwarningAmber input hints
warning_mutedMuted amber
amber_mutedProposed-skill inbox badges
Teal tiersteal_vividSelection/active in input + tools
teal_brightDialogs
teal_mutedCompleted/skipped plan tasks
teal_calmPlan progress bars
Blue tiersblue_slateHelp text, input placeholders
blue_steelInformational accents (sessions, files, projects)
blue_linkMarkdown links
blue_skyProjects
blue_softChat accents
blue_vividOnboarding voice brand accent
blue_codeInline code (markdown)
Surfacesselection_bgSelected text in the composer
surface_panelMission-control panel background
surface_qrQR panel background (onboarding)
surface_codeCode-block background
surface_code_altCode-block background, alternate shade
InkinkThe main background canvas
Miscpurple_softProposed-brain-dedup inbox badges

Decorative animation cycles (like the rotating project badge colors) are deliberately not roles: they stay preset-agnostic.

Writing your own theme

Drop a file at ~/.opencrabs/themes/<name>.toml. The file stem is the theme name. All 43 keys are required; here is a complete valid theme (nord, from the curated pack):

accent = "#8fbcbb"
accent_teal = "#8fbcbb"
accent_soft = "#eceff4"
text_primary = "#eceff4"
text_secondary = "#8b95a7"
text_muted = "#767b84"
text_dim = "#9ca0a8"
gray = "#434c5e"
gray_mid = "#9ca0a8"
gray_detail = "#91959e"
gray_dim = "#7e838c"
gray_dark = "#6b707a"
gray_base = "#434c5e"
gray_light = "#d0d3d9"
gray_soft = "#afb3ba"
gray_muted = "#8d929a"
success = "#a3be8c"
analytics_green = "#a3be8c"
green_check = "#a3be8c"
error = "#bf616a"
error_soft = "#bf616a"
error_faded = "#6f4853"
warning = "#d08770"
warning_muted = "#9f6e62"
amber_muted = "#87625a"
teal_vivid = "#8fbcbb"
teal_bright = "#8fbcbb"
teal_muted = "#6d8c90"
teal_calm = "#5a7177"
blue_slate = "#698f9e"
blue_steel = "#88c0d0"
blue_link = "#81a1c1"
blue_sky = "#88c0d0"
blue_soft = "#648896"
blue_vivid = "#88c0d0"
blue_code = "#88c0d0"
selection_bg = "#505660"
surface_panel = "#3b4252"
surface_qr = "#343a45"
surface_code = "#434c5e"
surface_code_alt = "#494e59"
ink = "#2e3440"
purple_soft = "#81a1c1"

Validation rules

Validation is loud, never silent. A theme file is rejected, with the reason shown by /theme list, when it:

  1. misses any of the 43 roles: the error names the missing key;
  2. carries an unknown key: strict typo guard, there is no partial-schema mode;
  3. uses a malformed value: only #RRGGBB or RRGGBB, case-insensitive;
  4. fails the contrast floor (eight reading-critical (foreground, background) pairs must hit 2.5:1 WCAG contrast: text_primary/text_secondary/accent/success/error/ warning on ink, blue_code on surface_code, and gray_mid on surface_panel. Deliberately dim tiers (text_muted, text_dim, …) are excluded) dim is their job;
  5. collides with a built-in name: user files can never shadow a shipped preset.

Everything else is free for the runtime: each valid theme gets its ANSI-256 fallback tier derived automatically, so terminals without truecolor still render it (nearest index in the 6×6×6 cube, grayscale ramp for neutrals).

Theme enforcement (v0.5.3)

Every widget in the TUI now resolves its colours through the theme engine, the last hardcoded ANSI sites are gone, and a suite-level guard fails the build if a new raw ANSI colour site appears (#1634). Themes can also declare an optional canvas background (the source background carries through catalog conversion), so a theme can restyle the whole terminal canvas, not just the widgets on it.

Imported themes

The 31-theme curated pack was generated by the in-tree converter (tui::theme_catalog) from two upstream formats:

  • alacritty-theme TOML ([colors.primary] background/foreground plus the 16 ANSI colors): the alacritty/alacritty-theme catalog, 176 themes;
  • opencode theme JSON (defs + theme token maps with dark/light variants, hex strings, ANSI integers, defs references and "none"), the sst/opencode built-in themes, 33 assets.

Both convert through a fixed 43-role mapping (semantic token first, ANSI color or deterministic bg/fg mix as fallback), and every generated file is pre-certified by the same validator user themes face: a converted file that doesn’t validate never ships. Each pack file carries a # source: provenance header naming the upstream repo, file, and fetch date; the gallery table shows it. Upstream palettes belong to their authors; the pack imports their colors, not their names’ goodwill.

The converter is generation-time tooling: the TUI itself only knows the embedded presets and your drop-in files.