Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Only write entries that are worth mentioning to users.

## Unreleased

- Shell: Add user-customizable color skins — describe a complete color palette in `~/.kimi/skins/<name>.yaml` and activate it with `/skin <name>` at runtime or `skin = "<name>"` in your config file; all color tokens (diff highlights, task browser, prompt completion menu, bottom toolbar, MCP status indicators) can be overridden per-skin with hex values, and missing tokens fall back to the dark defaults; the built-in `dark` and `light` themes are unchanged and the legacy `/theme` command continues to work

## 1.41.0 (2026-04-30)

- Plugin: Support installing plugins directly from a `.zip` URL — `kimi plugin install` now accepts HTTP(S) URLs ending in `.zip` (e.g. GitHub/GitLab archive links like `.../archive/refs/heads/main.zip`) and downloads + extracts them before resolving `plugin.json`, in addition to the existing git URL, local directory, and local zip-file sources
Expand Down
35 changes: 34 additions & 1 deletion docs/en/reference/slash-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Slash commands are built-in commands for Kimi Code CLI, used to control sessions, configuration, and debugging. Enter a command starting with `/` in the input box to trigger.

::: tip Shell mode
Some slash commands are also available in shell mode, including `/help`, `/exit`, `/version`, `/editor`, `/theme`, `/changelog`, `/feedback`, `/export`, `/import`, and `/task`.
Some slash commands are also available in shell mode, including `/help`, `/exit`, `/version`, `/editor`, `/theme`, `/skin`, `/changelog`, `/feedback`, `/export`, `/import`, and `/task`.
:::

## Help and info
Expand Down Expand Up @@ -77,6 +77,39 @@ Usage:

After switching, the configuration is saved to `config.toml` and the shell reloads automatically. The light theme adjusts colors for diff highlights, the task browser, the prompt completion menu, the bottom toolbar, and MCP status indicators to work well on light terminal backgrounds. You can also set `theme = "light"` directly in your config file — see [Config files](../configuration/config-files.md).

### `/skin`

Switch to a custom color skin. Skins are YAML files stored in `~/.kimi/skins/<name>.yaml` and can override every color token used by the UI.

Usage:

- `/skin`: Show the current skin and list all available skins
- `/skin <name>`: Switch to the named skin

A skin file uses the following structure:

```yaml
name: my-skin
description: My custom dark skin
colors:
diff_add_bg: "#12261e"
diff_del_bg: "#2d1214"
mcp_connected: "#56d364"
# ... any subset of the ~50 color tokens
branding:
prompt_symbol: "❯" # optional; replaces the default prompt character
welcome: "Hello" # optional; shown at startup
goodbye: "Goodbye" # optional; shown at exit
font:
primary: "Fira Code" # optional hint; displayed in /skin output
Comment thread
VrtxOmega marked this conversation as resolved.
Outdated
```

Any color token omitted from the file falls back to the dark-theme default. The built-in `dark` and `light` skins are always available. After switching, the skin name is saved to `config.toml` as `skin = "<name>"` and the shell reloads automatically. You can also set `skin = "<name>"` directly in your config file. See [Config files](../configuration/config-files.md) for details.

::: tip
`/skin` and `/theme` are independent. When a custom skin is active, `/theme` output still reflects `dark` or `light` for backwards compatibility, but the active skin's colors take effect.
:::

### `/reload`

Reload the configuration file without exiting Kimi Code CLI.
Expand Down
35 changes: 34 additions & 1 deletion docs/zh/reference/slash-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
斜杠命令是 Kimi Code CLI 的内置命令,用于控制会话、配置和调试。在输入框中输入 `/` 开头的命令即可触发。

::: tip Shell 模式
部分斜杠命令在 Shell 模式下也可以使用,包括 `/help`、`/exit`、`/version`、`/editor`、`/theme`、`/changelog`、`/feedback`、`/export`、`/import` 和 `/task`。
部分斜杠命令在 Shell 模式下也可以使用,包括 `/help`、`/exit`、`/version`、`/editor`、`/theme`、`/skin`、`/changelog`、`/feedback`、`/export`、`/import` 和 `/task`。
:::

## 帮助与信息
Expand Down Expand Up @@ -77,6 +77,39 @@

切换后配置会保存到 `config.toml` 并自动重新加载。浅色主题会调整 Diff 高亮、任务浏览器、提示符补全菜单、底部工具栏和 MCP 状态等所有 UI 组件的颜色,以适配浅色终端背景。也可以直接在配置文件中设置 `theme = "light"`,详见 [配置文件](../configuration/config-files.md)。

### `/skin`

切换到自定义配色皮肤。皮肤为存放在 `~/.kimi/skins/<name>.yaml` 中的 YAML 文件,可覆盖 UI 中所有颜色 token。

用法:

- `/skin`:显示当前皮肤并列出所有可用皮肤
- `/skin <name>`:切换到指定名称的皮肤

皮肤文件格式如下:

```yaml
name: my-skin
description: 我的自定义深色皮肤
colors:
diff_add_bg: "#12261e"
diff_del_bg: "#2d1214"
mcp_connected: "#56d364"
# ... 约 50 个颜色 token 中的任意子集
branding:
prompt_symbol: "❯" # 可选;替换默认提示符字符
welcome: "你好" # 可选;启动时显示
goodbye: "再见" # 可选;退出时显示
font:
primary: "Fira Code" # 可选提示;显示在 /skin 输出中
Comment thread
VrtxOmega marked this conversation as resolved.
Outdated
```

文件中省略的颜色 token 会回退到深色主题默认值。内置的 `dark` 和 `light` 皮肤始终可用。切换后皮肤名会以 `skin = "<name>"` 的形式保存到 `config.toml` 并自动重新加载。也可以直接在配置文件中设置 `skin = "<name>"`,详见 [配置文件](../configuration/config-files.md)。

::: tip 提示
`/skin` 与 `/theme` 相互独立。当自定义皮肤激活时,`/theme` 的输出仍会显示 `dark` 或 `light`(向后兼容),但实际生效的是当前皮肤的颜色。
:::

### `/reload`

重新加载配置文件,无需退出 Kimi Code CLI。
Expand Down
4 changes: 4 additions & 0 deletions src/kimi_cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ class Config(BaseModel):
default="dark",
description="Terminal color theme. Use 'light' for light terminal backgrounds.",
)
skin: str = Field(
default="",
description="Custom terminal skin name. Loads from ~/.kimi/skins/<skin>.yaml. Overrides theme when set.",
)
show_thinking_stream: bool = Field(
default=True,
description=(
Expand Down
10 changes: 7 additions & 3 deletions src/kimi_cli/ui/shell/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,11 +358,15 @@ async def _route_prompt_events(
async def run(self, command: str | None = None) -> bool:
_run_start_time = time.monotonic()

# Initialize theme from config
# Initialize theme/skin from config
if isinstance(self.soul, KimiSoul):
from kimi_cli.ui.theme import set_active_theme
from kimi_cli.ui.theme import set_active_skin, set_active_theme

set_active_theme(self.soul.runtime.config.theme)
config = self.soul.runtime.config
if getattr(config, "skin", ""):
set_active_skin(config.skin)
Comment thread
VrtxOmega marked this conversation as resolved.
Outdated
else:
set_active_theme(config.theme)

if command is not None:
# run single command and exit
Expand Down
1 change: 1 addition & 0 deletions src/kimi_cli/ui/shell/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,7 @@ def _build_toolbar_tips(clipboard_available: bool) -> list[str]:
"ctrl-j: newline",
"/feedback: send feedback",
"/theme: switch dark/light",
"/skin: switch terminal skin",
]
if clipboard_available:
tips.append("ctrl-v: paste clipboard")
Expand Down
61 changes: 61 additions & 0 deletions src/kimi_cli/ui/shell/slash.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,67 @@ def theme(app: Shell, args: str):
raise Reload(session_id=soul.runtime.session.id)


@registry.command
@shell_mode_registry.command
def skin(app: Shell, args: str):
"""Switch terminal skin (built-in or from ~/.kimi/skins/*.yaml)"""
from kimi_cli.ui.theme import get_active_skin_name, list_skins, set_active_skin

soul = ensure_kimi_soul(app)
if soul is None:
return

current = get_active_skin_name()
arg = args.strip()

if not arg:
console.print(f"Current skin: [bold]{current}[/bold]")
available = list_skins()
console.print("[grey50]Available skins:[/grey50]")
for name, desc in available:
marker = " → " if name == current else " "
console.print(f"{marker}[cyan]{name}[/cyan] {desc}")
console.print("[grey50]Usage: /skin <name>[/grey50]")
return

arg_lower = arg.lower()
if not set_active_skin(arg_lower):
console.print(f"[red]Unknown skin: {arg}.[/red]")
available = [name for name, _ in list_skins()]
if available:
console.print(f"[grey50]Available: {', '.join(available)}[/grey50]")
return
Comment thread
VrtxOmega marked this conversation as resolved.

if arg_lower == current:
console.print(f"[yellow]Already using {arg} skin.[/yellow]")
return
Comment thread
VrtxOmega marked this conversation as resolved.
Outdated

config_file = soul.runtime.config.source_file
if config_file is None:
console.print(
"[yellow]Skin switching requires a config file; "
"restart without --config to persist this setting.[/yellow]"
)
return

try:
config_for_save = load_config(config_file)
config_for_save.skin = arg_lower
# Also clear theme so skin takes precedence
if hasattr(config_for_save, "theme"):
config_for_save.theme = "dark"
save_config(config_for_save, config_file)
Comment thread
VrtxOmega marked this conversation as resolved.
except (ConfigError, OSError) as exc:
console.print(f"[red]Failed to save config: {exc}[/red]")
return

from kimi_cli.telemetry import track

track("skin_switch", skin=arg_lower)
console.print(f"[green]Switched to {arg_lower} skin. Reloading...[/green]")
raise Reload(session_id=soul.runtime.session.id)


@registry.command
def web(app: Shell, args: str):
"""Open Kimi Code Web UI in browser"""
Expand Down
Loading
Loading