Batonv0.3.9

Themes, styles & appearance

Baton separates colors (the theme) from shapes (the style). Any style works with any theme.

Styles

/style (or settings → Looks → Style) opens a gallery: moving through it previews each style on the whole app and in a miniature, Enter keeps it, Escape puts back exactly what you had.

StyleFramesStatus barBackground
classic (default)rounded boxes, titles in the borderplain bartheme
modernfilled title bars over raised panelschipstheme
minimala title rule onlyplain textterminal
accenta stripe in each agent's brand colorchipstheme
tabstitles in filled tabs on single-line boxeschipstheme
neonheavy boxes glowing in each agent's color, tabbed titleschipstheme
retrodouble-line boxes, compactplain bartheme
zentitle rules, compact cardsplain textterminal
paperthin single-line boxes, compact cardsplain texttheme
glassfilled title bars, cards tinted in each agent's colorchipsterminal
brutalistheavy boxes with tabbed titles, line spinner, compactplain bartheme

A style is a preset over these settings, each of which can be changed on its own (the style then shows as custom):

SettingOptions
ui.frame (/frame)line boxes · tab titles in filled tabs · bar filled title bars · minimal title rule · accent colored stripe
ui.borderbox lines for line / tab frames: rounded single heavy double ascii none
ui.status_styleplain bar · blocks (chips) · powerline (needs a Nerd / Powerline font) · minimal (text only)
ui.background (/background)theme: Baton paints the theme background · terminal: no background at all — your terminal's color, transparency and blur show through
ui.brand_borderstint every agent card with its brand color
ui.spinner, ui.densityas below

style = "modern" in a config file is enough: style keys you don't set yourself follow the chosen style.

Themes

Pick a theme live with ctrl+t: moving the selection previews the theme and Enter keeps it. You can also use /theme nord, baton theme set nord, [ui] theme = "nord" or BATON_THEME=nord. baton theme list shows them all with colour swatches.

Built in:

With appearance = "auto", Baton asks the terminal whether its background is dark or light and switches to the theme's counterpart if needed (for example mocha → latte, ayu-mirage → ayu-light, nightfox → dayfox).

Every built-in theme meets WCAG contrast against its background: at least 7:1 for text, 4.5:1 for muted text and diff lines, and 3:1 for subtle text. Where an upstream palette falls short, only the affected text tone is lifted just enough to pass (marked in packages/themes/src/builtin.ts); everything else is the upstream value.

Theme files

Put JSON files in ~/.config/baton/themes/ or <project>/.baton/themes/. The file name is the theme name. The format is OpenCode's, so OpenCode themes work as-is: Baton also reads ~/.config/opencode/themes/.

{
  "defs": { "ink": "#0f1117", "paper": "#e6e1cf", "ember": { "dark": "#ff8f40", "light": "#c2410c" } },
  "theme": {
    "background": "ink",
    "text": "paper",
    "primary": "ember",
    "agentClaude": "ember",
    "backgroundPanel": "none",
    "accent": 39
  }
}

A color value can be:

Tokens you leave out fall back to Baton's default theme, so a theme can be three lines long.

base16 / base24: drop a scheme .yaml file (with base00…base0F) into the same folders. Hundreds of schemes from tinted-theming work this way.

Tokens

GroupTokens
coreprimary secondary accent error warning success info text textMuted textSubtle
surfacesbackground backgroundPanel backgroundElement backgroundOverlay border borderActive borderSubtle selection
diffsdiffAdded diffRemoved diffContext diffAddedBg diffRemovedBg diffLineNumber diffAddedLineNumberBg diffRemovedLineNumberBg
agent statesstateIdle stateBusy stateWaiting stateError stateDone spinner
chromestatusBar statusText busTime busFrom busTo busBody mention toolName toolArgs thought
agent brandsagentClaude agentCodex agentOpencode agentGemini agentCursor agentCopilot agentAmp agentGoose agentQwen agentKiro agentDroid agentCline agentDefault

Beyond colors

SettingOptions
ui.layout (ctrl+l)grid: orchestrator on top, agent cards and the bus below · focus: one agent zoomed · swarm: a one-line prompt and a dense grid · wide: orchestrator column on the left
ui.borderrounded single heavy double ascii none
ui.iconsauto (real logos when the terminal supports Kitty graphics or Sixel, otherwise Unicode) · unicode (✱ >_ ⌬ ✦ ◆ …) · nerd · ascii ([CX])
ui.render_stylenative (each agent looks like its own CLI: Claude ● Read(…) / ⎿, Codex • Ran … / └) · unified
ui.spinnerstar dots circle moon arc pulse bounce line diamond
ui.verbsyour own spinner words (Spelunking…, Wrangling…)
ui.densitycomfy compact
ui.card_fieldswhich fields an idle agent's card shows
ui.status_left / ui.status_rightformat strings (see configuration.md)
[agent_style.<adapter or name>]icon, color, name_pattern

Logos

Logos are drawn with the Kitty graphics protocol (kitty, Ghostty, WezTerm, Konsole, iTerm2, Warp) or Sixel (foot, WezTerm, Windows Terminal, VS Code), as detected by OpenTUI. On other terminals Baton falls back to coloured glyphs.

Inside tmux, run set -g allow-passthrough on for logos to work. To turn logos off, set BATON_NO_IMAGES=1 or ui.icons = "unicode".

Baton 0.3.9 · MIT · Edit this page on GitHub