# Themes


A theme maps named color tokens to RGB values. The terminal UI styles every span — message text, tool cards, diffs, markdown, syntax highlighting — by looking up a token in the active theme. kli ships two built-in themes, `dark` and `light`, and chooses between them by reading the terminal background unless you pin one.

## Selecting a theme

The `theme` key in `settings.json` sets the active theme. Settings are read from `~/.config/kli/settings.json` (global) and `<repo>/.kli/settings.json` (project); the project value overrides the global one.

| Value | Effect |
| --- | --- |
| `"auto"` | Detect the terminal background at startup and select `dark` or `light`. |
| absent | Same as `"auto"`. |
| `"dark"` | Pin the dark theme. No detection. |
| `"light"` | Pin the light theme. No detection. |
| any registered theme name | Pin that theme. No detection. |

An unknown name is ignored with a warning, and the previous active theme stays in effect. A pinned theme suppresses background detection for the rest of the session.

```json
{
  "theme": "dark"
}
```

## Background detection

When `theme` is `"auto"` or absent, kli resolves `dark` or `light` at startup from the terminal background color. Detection runs only when standard input is a TTY and the `STY` environment variable is unset (it is skipped under GNU `screen`).

Resolution proceeds in order:

1. **OSC 11 query.** kli writes the OSC 11 background-color query followed by a DA1 (Device Attributes) request, then reads the reply with a 150 ms deadline. A reply of the form `rgb:RRRR/GGGG/BBBB` (8-bit or 16-bit channels, BEL- or ST-terminated) yields an RGB triple. The DA1 reply arriving first marks the terminal as not supporting the query.
2. **Luminance classification.** An RGB triple is converted to WCAG relative luminance after undoing sRGB gamma. Luminance below `0.5` classifies as `dark`; at or above `0.5` classifies as `light`.
3. **COLORFGBG fallback.** When the OSC 11 query returns no color (unsupported or timed out), the trailing background index of the `COLORFGBG` environment variable decides. Indices `0`–`6` and `8` read as `dark`; `7` and `9`–`15` read as `light`; any other value is treated as unset.
4. **Default.** With no usable signal from either source, the background resolves to `dark`.

Keystrokes typed during the query window are buffered and replayed after detection, so the handshake does not drop input.

## Token inventory

Every built-in theme defines the same set of tokens. A token whose value is empty resolves to the terminal default foreground (no color emitted). Tokens ending in `Bg` are background colors; the rest are foreground colors.

### Core

| Token | Role |
| --- | --- |
| `text` | Default message text. |
| `accent` | Accent color for emphasis. |
| `muted` | De-emphasized text. |
| `dim` | Further de-emphasized text. |
| `border` | Default border. |
| `borderAccent` | Accented border. |
| `borderMuted` | De-emphasized border. |
| `success` | Success state. |
| `error` | Error state. |
| `warning` | Warning state. |
| `selectedBg` | Background of the selected item. |
| `thinkingText` | Thinking-stream text. |
| `bashMode` | Bash-mode indicator. |

### Messages

| Token | Role |
| --- | --- |
| `userMessageBg` | User message background. |
| `userMessageText` | User message text. |
| `customMessageBg` | Custom message background. |
| `customMessageText` | Custom message text. |
| `customMessageLabel` | Custom message label. |

### Tool cards

| Token | Role |
| --- | --- |
| `toolPendingBg` | Pending tool-call background. |
| `toolSuccessBg` | Succeeded tool-call background. |
| `toolErrorBg` | Failed tool-call background. |
| `toolTitle` | Tool-call title. |
| `toolOutput` | Tool output text. |
| `toolDiffAdded` | Added line in a diff. |
| `toolDiffRemoved` | Removed line in a diff. |
| `toolDiffContext` | Unchanged context line in a diff. |

### Markdown

| Token | Role |
| --- | --- |
| `mdHeading` | Heading. |
| `mdLink` | Link text. |
| `mdLinkUrl` | Link URL. |
| `mdCode` | Inline code. |
| `mdCodeBlock` | Code block body. |
| `mdCodeBlockBorder` | Code block border. |
| `mdQuote` | Blockquote text. |
| `mdQuoteBorder` | Blockquote border. |
| `mdHr` | Horizontal rule. |
| `mdListBullet` | List bullet. |

### Syntax highlighting

| Token | Role |
| --- | --- |
| `syntaxComment` | Comment. |
| `syntaxKeyword` | Keyword. |
| `syntaxFunction` | Function name. |
| `syntaxVariable` | Variable. |
| `syntaxString` | String literal. |
| `syntaxNumber` | Numeric literal. |
| `syntaxType` | Type name. |
| `syntaxOperator` | Operator. |
| `syntaxPunctuation` | Punctuation. |

### Thinking levels

| Token | Role |
| --- | --- |
| `thinkingOff` | Thinking disabled. |
| `thinkingMinimal` | Minimal thinking. |
| `thinkingLow` | Low thinking. |
| `thinkingMedium` | Medium thinking. |
| `thinkingHigh` | High thinking. |
| `thinkingXhigh` | Extra-high thinking. |

## Color rendering

Token colors are RGB and render according to the detected terminal color mode. With `COLORTERM` set to `truecolor` or `24bit`, kli emits 24-bit color. With `256color` in `TERM`, each color is mapped to the nearest xterm-256 index by a redmean perceptual distance over the 6×6×6 color cube and the 24-step gray ramp. Otherwise no color is emitted and text renders plain.

## Related

- [Configuration reference](/kli/config/settings) — every `settings.json` key.
- [Keymap](/kli/commands/keymap) — default key bindings.
