feat: add user-customizable color skins via YAML - #2170
Closed
VrtxOmega wants to merge 3 commits into
Closed
Conversation
- Rewrite theme.py with Skin dataclass supporting arbitrary color palettes - Backwards-compatible: theme='dark'|'light' still works as before - Add skin field to config.py for custom skin names - Add /skin slash command to switch skins at runtime - Load custom skins from ~/.kimi/skins/<name>.yaml (Hermes format) - Built-in skins: dark, light - Custom skins discovered dynamically from filesystem - Add /skin to prompt help text
- tests/ui/test_skin_system.py: full coverage of SkinColors/Skin/SkinBranding dataclasses, _load_yaml_skin (valid/partial/bad YAML), _discover_custom_skins filesystem discovery, public set/get/list_skins API, backwards-compat set_active_theme/get_active_theme, and all five color-resolver functions - CHANGELOG.md: add Unreleased entry describing /skin and skin= config - docs/en/reference/slash-commands.md: add /skin section with YAML format reference; add /skin to shell-mode tip list - docs/zh/reference/slash-commands.md: Chinese translation of same Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new “skin” system that lets users load custom UI color palettes from YAML files under ~/.kimi/skins/ and switch them at runtime via a new /skin slash command, while aiming to preserve existing dark/light theme behavior for backwards compatibility.
Changes:
- Add skin dataclasses + YAML loader/discovery and make all UI color resolver functions skin-aware (
src/kimi_cli/ui/theme.py). - Add
/skinslash command plus config integration (skin = "<name>") and shell startup initialization from config. - Add tests for parsing/discovery/public API, update docs (EN/ZH) and changelog.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
src/kimi_cli/ui/theme.py |
Implements skin model, YAML loading/discovery, and routes all color resolvers through the active skin. |
src/kimi_cli/ui/shell/slash.py |
Adds /skin command and persists config.skin. |
src/kimi_cli/ui/shell/__init__.py |
Initializes skin/theme from config on shell startup. |
src/kimi_cli/config.py |
Adds skin field to the config model. |
src/kimi_cli/ui/shell/prompt.py |
Adds /skin to toolbar tips. |
tests/ui/test_skin_system.py |
Adds new test suite covering skin dataclasses, YAML parsing, discovery, and resolver outputs. |
docs/en/reference/slash-commands.md |
Documents /skin usage and YAML structure. |
docs/zh/reference/slash-commands.md |
Documents /skin usage and YAML structure (Chinese). |
CHANGELOG.md |
Adds an Unreleased entry for the new skin feature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- theme.py: remove unused `import os` (F401) - theme.py: protect built-in skin names — _discover_custom_skins now skips any YAML whose resolved name collides with a built-in, so 'dark'/'light' are always guaranteed to be the built-in palettes - theme.py: split _all_skins() into a cached fast path + explicit _refresh_custom_skins(); color resolvers no longer trigger a filesystem scan on every prompt render; only set_active_skin() and list_skins() refresh the cache (at call sites that already expect I/O) - slash.py: fix /skin persist-before-activate — validate skin existence via list_skins() set membership (no state mutation), then persist to config, then call set_active_skin(); matches the pattern established by the sibling /theme command - slash.py: remove theme-clobbering — /skin no longer overwrites config.theme to "dark", preserving the user's theme preference for when no custom skin is active - __init__.py: fall back to config.theme when config.skin is set but the skin cannot be found or loaded, instead of silently leaving the dark default regardless of the theme setting - docs: correct branding/font_hint claims — welcome/goodbye and font.primary are parsed and stored in the skin object but not rendered in the default shell UI; docs now say "available via API" rather than implying they appear in the UI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2171
Summary
/skinslash command — switch between named skins at runtime; works like/themebut for user-defined palettes~/.kimi/skins/<name>.yamlfiles define complete color palettes in a Hermes-compatible format; any omitted token falls back to the dark defaultsdarkandlightbuilt-ins are unchanged;/themestill works;get_active_theme()returns"dark"for custom skins so existing callers aren't brokenskin = "<name>"inconfig.tomlactivates a skin on startup, same lifecycle astheme/skinsection added to EN and ZH slash-commands reference; CHANGELOG entry under UnreleasedExample skin file
Test plan
pytest tests/ui/test_skin_system.py)test_console_theme.pyunaffectedmkdir -p ~/.kimi/skins && echo "name: test" > ~/.kimi/skins/test.yaml, then/skin testin kimi shell/skinwith no args lists available skinsskin = "test"in config.toml activates on startup/theme darkstill works after/skinswitch🤖 Generated with Claude Code