kimi-code/docs/en/customization/themes.md
liruifengv 2db5fc20ec
feat: add shell mode (!) to the CLI (#1079)
* feat: add shell mode (`!`) to the CLI

Add shell mode, letting users run shell commands directly from the prompt
with `!`. Output streams live into the transcript, supports backgrounding
(ctrl+b), cancellation (Esc / Ctrl+C), input queuing while running, and
enters the conversation context with resume support.

* feat(kimi-code): show shell mode label on editor border and add tip

Render a "! shell mode" label on the top-left of the editor border while the editor is in `!` bash mode, so the active mode is visible at a glance. Also add a rotating toolbar tip (`! to run a shell command`) to surface the feature.

* feat(kimi-code): refine shell mode queue, history, and display

- Keep `!` commands out of input history so they never resurface as bare text stripped of their `!`.

- Make `!` commands non-steerable: Ctrl-S skips them (they stay queued to run after the current task) and the steer hint is only shown when something is actually steerable.

- Render queued `!` commands with a `$` prompt and the shell-mode hue so they read as commands, not as text to send to the model.

- Echo executed shell commands with a `$` prompt instead of `!`.

* fix(kimi-code): sanitize shell output and harden rendering

Captured shell command output can contain terminal control sequences (colours, cursor moves, alternate-screen switches, OSC hyperlinks, carriage-return spinners, bells). pi-tui's Text passes strings straight to the terminal, so any unhandled sequence was executed by the terminal and fought with pi-tui's own cursor control, producing the blank-screen-plus-leftover-characters mess after running commands like pnpm dev or a nested TUI.

- Sanitize CSI (incl. private modes), OSC, single-char ESC and C0 control chars (keeping newline and tab) in both the finished/resume view (previously unsanitized) and the running tail.

- Make the sanitize, format, and ShellRunComponent render paths never-throw, and cap the live running buffer, so a misbehaving command cannot crash the TUI.

- Dispose transcript children on clear so ShellRunComponent's timer is released on /clear or session switch.

* fix(kimi-code): render shell command echo with $ instead of sparkles

The shell command echo is a 'user' transcript entry, so UserMessageComponent prefixed it with the USER_MESSAGE_BULLET (sparkles), producing 'sparkles $ command'.

Add an optional bullet override to UserMessageComponent / TranscriptEntry and set it to an empty string for the shell echo (both live and resume), so the '$ command' content sits at the leading column where the sparkles marker used to be. Normal user messages keep the sparkles bullet.

* fix(kimi-code): enter shell mode when pasting a !-prefixed command

The bash-mode trigger only handled the single ! keystroke, so a pasted !cmd was inserted as literal text in prompt mode and submitted as a normal message.

After pi-tui inserts pasted content, detect an empty-prompt buffer that now starts with !, switch to bash mode, and strip the leading ! so the buffer holds only the command, matching the typed ! path.

* fix(kimi-code): restore shell mode when recalling a queued command

recallLastQueued() dropped the queued item's mode, and the Up-arrow recall only restored the text. A queued ! command (queued while another command runs, which resets the editor to prompt mode) therefore came back as a normal prompt and was submitted as a message instead of a shell command.

Return the full QueuedMessage from recallLastQueued() and restore editor.inputMode (plus the onInputModeChange sync) from the recalled item's mode.

* feat(kimi-code): use violet as the shell mode color

Replace the claude-code-style magenta/rose shellMode token with a violet that is distinct from plan-mode blue, the user role amber, success green, error red, and the teal accent.

Custom themes that omit the token fall back to this new default via the base+overrides merge, so existing custom themes keep working unchanged.

* chore: refine the shell mode changeset

* docs: document shell mode

Add a Shell mode section to the interaction guide and list the ! and Ctrl+B shortcuts in the keyboard reference, in both English and Chinese.

* test(protocol): include shell events in volatile classification check

shell.output and shell.started were added as volatile event types for shell mode; update the snapshot test's volatile-type list and count accordingly.

* fix(agent-core): surface shell command failure reason with no output

When a ! shell command fails without producing stdout/stderr (non-zero exit with no output, timeout, spawn failure), the failure reason lived only in the tool result's output and the TUI showed '(no output)'. Fold it into stderr so the live view and replay show what went wrong.

* fix(kimi-code): decode CSI-u ! to enter shell mode

In terminals with the Kitty keyboard protocol (VSCode integrated terminal, Kitty), pressing ! arrives as a CSI-u sequence, so the raw normalized === '!' comparison never matched and shell mode could not be entered by typing !. Decode with printableChar before comparing, matching every other printable-key check in the TUI.

* fix(kimi-code): do not steer while a shell command is running

Ctrl-S steers queued input into the running turn, but a shell command is not an agent turn, so steering during streamingPhase === 'shell' would launch a turn before the command output is recorded. Keep Ctrl-S a no-op during shell runs; queued messages stay queued.

* fix(agent-core): escape bash tag delimiters in shell output

Shell command output is arbitrary text; if it contains a bash tag delimiter such as </bash-stdout>, the recorded pseudo-XML wrapper breaks and replay extracts the wrong slice. Escape the content when wrapping it in agent-core and unescape when extracting during replay, so output survives round-trip intact.

* docs: document the shellMode theme token

The shellMode color token was added to the palette but not propagated to its mirrors. Add it to the custom-theme docs token table, the theme JSON schema, and the custom-theme skill token list.

* feat(agent-core): reset background task deadline on detach

Add a resettable deadline timer to BackgroundManager and let tasks register a detach timeout; when a foreground task is moved to the background, its deadline resets to the background default counted from the detach moment.

Wire this into shell mode so ! commands run with a 3-minute foreground timeout and get 10 minutes once detached to the background, instead of staying bounded by the original 60-second foreground deadline.

* feat(agent-core): lower shell mode foreground timeout to 2 minutes
2026-06-25 21:24:53 +08:00

5.9 KiB

Custom Themes

Kimi Code CLI can use a built-in color scheme or a custom JSON theme file. Custom files live in the themes directory and appear in /theme alongside the built-in choices.

Built-in color tokens

Custom themes can override the tokens below. The dark and light columns show the built-in values; auto resolves to one of those palettes at startup, and falls back to dark when terminal background detection is unavailable.

Token dark light What it controls
primary #4FA8FF #1565C0 The most-used color. Links, inline code, the selected item in nearly every dialog, the focused editor border, Plan/"running" badges, spinners
accent #5BC0BE #00838F Secondary highlight. Approval prefix, device-code box, image placeholder, BTW / queue panes, registry import
text #E0E0E0 #1A1A1A Body text. Dialog bodies, todo titles, footer model label, Markdown headings, assistant/tool message bullets, list bullets
textStrong #F5F5F5 #1A1A1A Emphasized / bold text. Input dialogs, status messages
textDim #888888 #454545 Secondary, dimmed text. Thinking, hints, descriptions, completed todos, Markdown quotes, footer status bar
textMuted #6B6B6B #5F5F5F Faintest text. Counters, scroll info, descriptions, Markdown link URLs, code-block borders
border #5A5A5A #737373 Pane and editor borders, Markdown horizontal rule
borderFocus #E8A838 #92660A Focus / attention border, currently only the approval panel
success #4EC87E #0E7A38 Success state. , "enabled", completed
warning #E8A838 #92660A Warning state. auto/yolo badges, stale markers, Plan mode hint
error #E85454 #B91C1C Error state. Error messages, failed tool output
diffAdded #4EC87E #0E7A38 Diff added lines
diffRemoved #E85454 #B91C1C Diff removed lines
diffAddedStrong #7AD99B #0E7A38 Diff intra-line changed words, added and bold
diffRemovedStrong #F08585 #B91C1C Diff intra-line changed words, removed and bold
diffGutter #6B6B6B #737373 Diff line-number gutter
diffMeta #888888 #5F5F5F Diff meta / hunk headers
roleUser #FFCB6B #9A4A00 User message bullet and text, skill-activation name
shellMode #BD93F9 #7C3AED Shell mode (!) prompt, editor border, and the echoed $ command line

Use the custom-theme skill

You do not need to write the JSON by hand. Run the built-in /custom-theme [extra text] skill command to enter the custom-theme workflow; the skill can choose colors, write the file under ~/.kimi-code/themes/, validate the hex values, and tell you how to apply it.

Example invocations:

  • /custom-theme Create a warm dark theme with amber accents.
  • /custom-theme Make a light theme based on Solarized, but keep errors easy to see.
  • /custom-theme Tweak my ember theme so diffs have higher contrast.

After activation, the skill usually asks whether you want a light or dark base, what mood or palette you prefer, and whether you have exact colors to include. If you use it to edit an existing theme, make sure it reads and backs up the file before overwriting it.

Create a theme

Add a .json file to the themes directory:

  • ~/.kimi-code/themes/
  • or $KIMI_CODE_HOME/themes/ when the KIMI_CODE_HOME environment variable is set

Create the directory if it does not exist. The filename is the theme name: ember.json appears in /theme as Custom: ember.

A minimal theme only sets the colors you want to change; the rest fall back to the base palette (dark by default):

{
  "name": "ember",
  "colors": {
    "primary": "#83A598",
    "accent": "#FE8019"
  }
}

Fields:

  • name (required): the theme identifier.
  • displayName (optional): a human-readable name.
  • base (optional): the built-in palette that unspecified tokens inherit — "dark" (default) or "light". Set "base": "light" when you are building a light theme so the tokens you leave out stay readable on a light background (otherwise they fall back to the dark palette).
  • colors (optional): the color tokens to override, each a 6-digit hex value (e.g. #FE8019).

Use the token names from Built-in color tokens. Any token you omit falls back to the selected base palette, so partial themes are fine:

{
  "name": "just-blue",
  "colors": {
    "primary": "#3B82F6",
    "roleUser": "#3B82F6"
  }
}

Select a theme

Two ways:

  1. The /theme command (recommended): opens the theme picker, where custom themes appear as Custom: <filename>. The picker re-scans the themes directory every time it opens, so a theme file you just added shows up without a restart.

  2. tui.toml: set theme to your theme name:

    # ~/.kimi-code/tui.toml
    theme = "ember"
    

What happens on errors

Custom themes are designed to never get in your way:

  • An invalid color value (not # followed by 6 hex digits): that one entry is silently skipped and falls back to the selected base palette; the rest of the colors still apply.
  • An unrecognized token: ignored, with no effect on other colors.
  • A missing custom theme file or malformed JSON: silently falls back to the built-in dark palette. It does not retry auto.

Editing the active theme

If you edit the theme file that is currently active, the change is not reloaded automatically. To apply the new colors:

  • run /reload-tui — it reloads tui.toml and re-applies the current theme (including re-reading the theme file); or
  • switch to another theme in /theme and back.

::: warning Note Re-selecting the same theme in /theme does not reload it (you get a "Theme unchanged" message). To reload changes to the active theme, use one of the two methods above. :::