Skip to content

feat: add user-customizable color skins via YAML - #2170

Closed
VrtxOmega wants to merge 3 commits into
MoonshotAI:mainfrom
VrtxOmega:feat/yaml-skin-system
Closed

feat: add user-customizable color skins via YAML#2170
VrtxOmega wants to merge 3 commits into
MoonshotAI:mainfrom
VrtxOmega:feat/yaml-skin-system

Conversation

@VrtxOmega

@VrtxOmega VrtxOmega commented May 6, 2026

Copy link
Copy Markdown

Closes #2171

Summary

  • New /skin slash command — switch between named skins at runtime; works like /theme but for user-defined palettes
  • YAML skin loader~/.kimi/skins/<name>.yaml files define complete color palettes in a Hermes-compatible format; any omitted token falls back to the dark defaults
  • Backwards-compatibledark and light built-ins are unchanged; /theme still works; get_active_theme() returns "dark" for custom skins so existing callers aren't broken
  • Config integrationskin = "<name>" in config.toml activates a skin on startup, same lifecycle as theme
  • 50 new tests — cover dataclasses, YAML parsing (valid/partial/bad), filesystem discovery, public API, backwards-compat bridge, and all five color-resolver functions
  • Docs updated/skin section added to EN and ZH slash-commands reference; CHANGELOG entry under Unreleased

Example skin file

name: dracula
description: Dracula color scheme
colors:
  diff_add_bg: "#1e3a2e"
  diff_del_bg: "#3a1e2e"
  mcp_connected: "#50fa7b"
  toolbar_yolo: "#ff79c6"
branding:
  prompt_symbol: ""
font:
  primary: "Fira Code"

Test plan

  • All 50 new tests pass (pytest tests/ui/test_skin_system.py)
  • Existing test_console_theme.py unaffected
  • Manual: mkdir -p ~/.kimi/skins && echo "name: test" > ~/.kimi/skins/test.yaml, then /skin test in kimi shell
  • Manual: verify /skin with no args lists available skins
  • Manual: verify skin = "test" in config.toml activates on startup
  • Manual: verify /theme dark still works after /skin switch

🤖 Generated with Claude Code

VrtxOmega and others added 2 commits May 6, 2026 03:01
- 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>
Copilot AI review requested due to automatic review settings May 6, 2026 18:29

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment thread src/kimi_cli/ui/shell/slash.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 /skin slash 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.

Comment thread src/kimi_cli/ui/theme.py Outdated
Comment thread src/kimi_cli/ui/theme.py Outdated
Comment thread src/kimi_cli/ui/shell/slash.py
Comment thread src/kimi_cli/ui/shell/__init__.py Outdated
Comment thread src/kimi_cli/ui/theme.py Outdated
Comment thread src/kimi_cli/ui/shell/slash.py
Comment thread docs/en/reference/slash-commands.md Outdated
Comment thread docs/zh/reference/slash-commands.md Outdated
- 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: user-customizable color skins via YAML (~/.kimi/skins/)

2 participants