Theme Architecture Handoff
Status: COMPLETED (2026-02-11)
All steps executed. The unified CSS variable contract is live. theme-nextstep.tcss deleted. Both palettes emit the same variable set. 14 themes supported.
Problem (historical)
A previous agent treated NeXTSTEP as one optional theme among many and created divergent variable sets between the tunacode and nextstep palettes. This led to:
UI_COLORS and NEXTSTEP_COLORS defining different variable keys
- Hardcoded hex in TCSS files
- 352 lines of per-theme CSS overrides in
theme-nextstep.tcss
- Any CSS referencing
$bevel-light broke in dark theme; $scrollbar-color broke in light theme
Resolution
NeXTSTEP is not a theme -- it is the structural design language. Every theme (dark, light, catppuccin, dracula, etc.) follows the same NeXTSTEP structural design: beveled borders, zone-based layout, 3D affordances, inset input fields, raised panels. A "theme" is only a color palette swap.
What was done
- Defined
THEME_VARIABLE_CONTRACT -- a single tuple of (css_variable, palette_key) pairs that every theme must satisfy
- Added
_build_theme_variables() with fail-fast validation for missing palette keys
- Both
UI_COLORS and NEXTSTEP_COLORS now include all 6 shared keys: bevel_light, bevel_dark, border, muted, scrollbar_thumb, scrollbar_track
- Both
build_tunacode_theme() and build_nextstep_theme() emit identical variable schemas via the contract
- Added
BUILTIN_THEME_PALETTES with 12 additional palettes (catppuccin-latte, catppuccin-mocha, dracula, flexoki, gruvbox, monokai, nord, solarized-light, textual-ansi, textual-dark, textual-light, tokyo-night)
wrap_builtin_themes() injects contract variables into Textual built-in themes
- All TCSS files rewritten to use only
$variables -- zero hardcoded hex
- Deleted
theme-nextstep.tcss and removed it from CSS_PATH in app.py
- Tests added:
tests/unit/ui/test_theme_variable_contract.py, tests/unit/ui/test_status_bar_layout.py
Verification
uv run pytest tests/unit/ui/ -q -- pass
uv run ruff check . -- pass
- Visual verification screenshots in
memory-bank/plan/assets/verification/
Current Architecture
See .claude/patterns/unified-css-theme-architecture.md for the canonical reference.
Reference
- CSS files:
src/tunacode/ui/styles/ (4 files: layout, panels, widgets, modals)
- Theme builders:
src/tunacode/constants.py
- CSS loading:
src/tunacode/ui/app.py CSS_PATH
- NeXTSTEP UI skill:
.claude/skills/neXTSTEP-ui/SKILL.md
1---2name: 2471-2026-02-11-theme-architecture-handoff-54ea85043description: Theme Architecture Handoff4---5# Theme Architecture Handoff67## Status: COMPLETED (2026-02-11)89All steps executed. The unified CSS variable contract is live. `theme-nextstep.tcss` deleted. Both palettes emit the same variable set. 14 themes supported.1011---1213## Problem (historical)1415A previous agent treated NeXTSTEP as one optional theme among many and created divergent variable sets between the tunacode and nextstep palettes. This led to:16171. `UI_COLORS` and `NEXTSTEP_COLORS` defining different variable keys182. Hardcoded hex in TCSS files193. 352 lines of per-theme CSS overrides in `theme-nextstep.tcss`204. Any CSS referencing `$bevel-light` broke in dark theme; `$scrollbar-color` broke in light theme2122## Resolution2324NeXTSTEP is not a theme -- it is the structural design language. Every theme (dark, light, catppuccin, dracula, etc.) follows the same NeXTSTEP structural design: beveled borders, zone-based layout, 3D affordances, inset input fields, raised panels. A "theme" is only a color palette swap.2526### What was done27281. Defined `THEME_VARIABLE_CONTRACT` -- a single tuple of `(css_variable, palette_key)` pairs that every theme must satisfy292. Added `_build_theme_variables()` with fail-fast validation for missing palette keys303. Both `UI_COLORS` and `NEXTSTEP_COLORS` now include all 6 shared keys: `bevel_light`, `bevel_dark`, `border`, `muted`, `scrollbar_thumb`, `scrollbar_track`314. Both `build_tunacode_theme()` and `build_nextstep_theme()` emit identical variable schemas via the contract325. Added `BUILTIN_THEME_PALETTES` with 12 additional palettes (catppuccin-latte, catppuccin-mocha, dracula, flexoki, gruvbox, monokai, nord, solarized-light, textual-ansi, textual-dark, textual-light, tokyo-night)336. `wrap_builtin_themes()` injects contract variables into Textual built-in themes347. All TCSS files rewritten to use only `$variables` -- zero hardcoded hex358. Deleted `theme-nextstep.tcss` and removed it from `CSS_PATH` in `app.py`369. Tests added: `tests/unit/ui/test_theme_variable_contract.py`, `tests/unit/ui/test_status_bar_layout.py`3738### Verification3940- `uv run pytest tests/unit/ui/ -q` -- pass41- `uv run ruff check .` -- pass42- Visual verification screenshots in `memory-bank/plan/assets/verification/`4344## Current Architecture4546See `.claude/patterns/unified-css-theme-architecture.md` for the canonical reference.4748## Reference4950- CSS files: `src/tunacode/ui/styles/` (4 files: layout, panels, widgets, modals)51- Theme builders: `src/tunacode/constants.py`52- CSS loading: `src/tunacode/ui/app.py` `CSS_PATH`53- NeXTSTEP UI skill: `.claude/skills/neXTSTEP-ui/SKILL.md`