aimux docs
Guides

Themes

Built-in themes, the theme picker, and typed theme helpers.

aimux themes are Shiki themes. The runtime works with full theme objects internally, while aimux.config.ts exposes startup theme selection plus palette overrides for the chosen base theme.

aimux ships:

  • Two house themes: aimux (teal accents on deep blue, default) and dracula-at-night (dark Dracula variant).
  • Every theme bundled by Shiki — dracula, tokyo-night, catppuccin-mocha, nord, one-dark-pro, github-dark, monokai, plus 58 others. 67 themes total.

Runtime theme picker

Open with Ctrl+T from navigation mode.

KeyAction
j / kPreview next / previous theme
/ Same
Ctrl+N / Ctrl+PSame
EnterConfirm selection (persists to aimux.json)
EscRestore the original theme and close
/Enter filter mode

In filter mode typing narrows by id or display name; Enter confirms, Esc clears.

Theme shape

A theme is a Theme object:

interface Theme {
  name: string // id (e.g. 'aimux')
  displayName: string // shown in picker
  type: 'dark' | 'light'
  fg: string // default foreground
  bg: string // default background
  colors: Record<string, string> // VSCode workbench color keys
  settings: ThemeTokenRule[] // TextMate token rules
  // plus optional tokenColors, colorReplacements, semantic*
}

colors is indexed by VSCode workbench keys (editor.background, sideBar.background, textLink.foreground, terminal.ansiRed, …). aimux's UI reads a documented subset directly from this map — no intermediate aliases.

Theme config

aimux.config.ts exposes a small typed theme surface:

import { defineConfig } from '@brimveyn/aimux-config'

export default defineConfig({
  theme: {
    initialMode: 'dark',
    paletteOverrides: {
      primary: '#7dd3fc',
      warning: '#fbbf24',
    },
  },
})
  • theme.initialMode is a startup override for the built-in light or dark family.
  • theme.paletteOverrides customizes the active palette on top of whichever base theme the runtime chooses.

This config does not replace the runtime theme picker. The picker still persists the selected theme id separately in aimux.json.

Key reference

aimux reads these VSCode keys from theme.colors at runtime. They're all guaranteed to be populated on every shipped theme (the build-time normalizer fills gaps via a fallback chain). User themes are normalized the same way at registration — missing keys resolve to a sensible default.

VSCode keyAimux uses it for
editor.backgroundapp background
editor.foregrounddefault text color
editor.lineHighlightBackgroundsubtle banding / dim backgrounds
editor.selectionBackgroundlist / text selection
editorLineNumber.foregrounddiff gutter, hint text
sideBar.backgroundside panels, surfaces
sideBarSectionHeader.backgroundsection headers
editorGroupHeader.tabsBackgroundtab strip
editorWidget.backgroundmodal / overlay backgrounds
editorGroup.borderpane separators
focusBorderactive tab / focused input
list.activeSelectionBackgroundselected list row
descriptionForegroundmuted / secondary text
textLink.foregroundaccents, headings
errorForeground / editorError.foregrounderrors, D git status
editorWarning.foregroundwarnings, M git status
terminal.ansiRed/Green/Yellow/Blue/Magenta/CyanANSI-style accents in UI
gitDecoration.addedResourceForegroundadditions, A git status
gitDecoration.modifiedResourceForegroundmodified files
gitDecoration.deletedResourceForegrounddeleted files
gitDecoration.untrackedResourceForegrounduntracked files
diffEditor.insertedLineBackgrounddiff add background
diffEditor.removedLineBackgrounddiff remove background

The full list lives in AIMUX_COLOR_KEYS (@brimveyn/aimux-config). Themes can also define any other VSCode key — aimux preserves extra entries so highlighter.loadTheme(theme) sees them exactly as shipped.

Syntax highlighting

Every theme carries real TextMate settings. The diff view calls highlighter.loadTheme(THEMES[id]) directly — the colors you see in the UI and the colors on code tokens come from the same theme object.

Persistence & migration

  • Picker writes themeId to aimux.json on confirm.
  • On next launch: persisted id → theme.initialMode → built-in dark fallback.
  • theme.paletteOverrides applies on top of the chosen base theme.
  • Legacy ids renamed to shiki equivalents are auto-migrated:
old idresolves to
everforesteverforest-dark
gruvbox-darkgruvbox-dark-hard
kanagawakanagawa-wave
one-darkone-dark-pro

Migrating from the old palette API

Earlier aimux versions exposed a 17-field ThemeColors alias (accent, panel, textMuted, …). Those aliases are gone. Rewrite user themes using VSCode keys:

old aliasVSCode key
backgroundeditor.background
texteditor.foreground
textMuteddescriptionForeground
panelsideBar.background
panelMutedsideBarSectionHeader.background
panelHighlightlist.activeSelectionBackground
overlayeditorWidget.background
bordereditorGroup.border
borderActivefocusBorder
dimeditor.lineHighlightBackground
accenttextLink.foreground
accentAltterminal.ansiMagenta
warningeditorWarning.foreground
dangereditorError.foreground
successgitDecoration.addedResourceForeground
diffAddBgdiffEditor.insertedLineBackground
diffRemoveBgdiffEditor.removedLineBackground

Beta — Harmonize Claude Code colors

Aimux can push the active theme into Claude Code itself so the assistant's output matches the rest of the app. Off by default.

// aimux.config.ts
export default defineConfig({
  theme: {
    initialId: 'aimux',
    beta: {
      harmonizeClaudeTheme: true,
    },
  },
})

When the flag is on:

  • aimux writes ~/.claude/themes/aimux.json from the resolved aimux palette.
  • aimux sets "theme": "custom:aimux" in ~/.claude/settings.json (other fields preserved, write is atomic).
  • Switching theme inside aimux rewrites the file. Claude Code watches its themes dir and repaints live without restarting the session.

Mapping (Claude token → aimux token): claudeaccent, errorerror, successsuccess, warningwarning, planModeinfo, bashBorderwarning, promptBorderborder, diffAddeddiffAddedBg, diffRemoveddiffRemovedBg, userMessageBackgroundbackgroundPanel, texttext, inactivetextMuted. Tokens we don't override (Shimmer variants, dim diffs, subagent colors) fall through to Claude's dark/light preset.

Requirements: Claude Code v2.1.118 or later. Limits: Claude's truecolor escapes (24-bit hex) bypass the theme — those colors stay native.

To revert: turn the flag off and either delete ~/.claude/themes/aimux.json or pick a different theme via Claude's /theme command.

Note: while the flag is on, aimux re-asserts theme: "custom:aimux" in ~/.claude/settings.json on every launch. Picking a different theme via Claude's /theme command will be reverted next time aimux starts. Disable the flag first if you want to use Claude's own theme picker.

Beta — Re-tokenize Claude code blocks (experimental)

Claude Code's syntax highlighting (Monokai-Extended) is hardcoded and not exposed by the custom-theme API (anthropics/claude-code#48636), so colored code on diff lines and Read/Edit listings shadows the aimux diff backgrounds. This flag disables Claude's built-in highlighting and re-colors code blocks with the active aimux theme via shiki.

theme: {
  beta: {
    harmonizeClaudeTheme: true,
    experimentalSyntaxHighlight: true,
  },
},

When the flag is on:

  • CLAUDE_CODE_SYNTAX_HIGHLIGHT=false is exported to child processes before the daemon spawns, so Claude emits plain code (no embedded Monokai escapes).
  • Aimux pre-warms shiki with ~25 common languages.
  • Tool headers (Update(src/foo.ts), Read(...), Edit(...), Write(...), MultiEdit(...), Create(...), NotebookEdit(...)) are parsed to infer the language from the file extension. Per-tab cache means blocks whose header scrolled out of the viewport still get colored correctly.
  • Code lines (any line whose prefix matches ^\s*\d+\s+([+-]\s+)?) are detected, the gutter (line number + diff marker) is preserved, and the code text is replaced with shiki tokens.
  • The whole row is repainted with a strip background (the active theme's diffAddedBg / diffRemovedBg for diff lines, or backgroundElement for non-diff Read/Edit context). The strip starts at the line number — leading whitespace before the gutter stays on backgroundElement to match the surrounding tool zone. The strip pads to the snapshot's max line width so window resizes don't leave ragged ends.
  • Only semantically meaningful tokens get a color (keyword, string, comment, number, type, function name). Operators / punctuation / variables fall back to plain text so the highlight stays calm instead of rainbow.

Requirements: same as above (Claude Code v2.1.118+). Toggling the flag requires a full aimux restart (and aimux restart-daemon if a previous daemon is still running with the old env).

Limits — this is a POC:

  • Language inference relies on the tool header being visible at least once per tab; before the first header, blocks fall back to TypeScript.
  • Extensions outside the supported set (e.g. .zig, .elm) fall back to TypeScript tokenization, which produces best-effort coloring.
  • The overlay runs on every tab, not just claude ones — bash/sh tabs that print numbered lines (ls -1, cat -n) will also get recolored.
  • Fragile against Claude UI changes: if Claude alters its tool header format or line-number gutter, detection breaks silently and the overlay becomes a no-op.

On this page