Themes & UI v1.0
Color palettes, layout anatomy, tool rendering, and keyboard navigation for the Automergent terminal UI.
Theme System Overview
Automergent ships with 11 built-in color themes, each defining a complete 16-slot color palette plus 50+ pre-built lipgloss styles derived from those colors. Themes are hot-swappable at runtime — every renderer, diff pane, markdown block, and tool card repaints instantly.
16 Color Slots per Theme
Every theme must fill these 16 named color slots, defined in internal/tui/themes/theme.go:
| Slot | Purpose | Usage |
|---|---|---|
Background | Primary background | Terminal bg, pane fill, code blocks |
Surface | Raised surfaces | User bubbles, tool slabs, input bg, diff bg |
Overlay | Overlays & secondary | Dropdown bg, inactive borders, menu dims |
Text | Primary text | Body text, headings, bold elements |
Subtext | Secondary text | Labels, hints, descriptions, timestamps |
Muted | De-emphasized text | Dim text, status bar, system messages |
Accent | Primary accent | Links, focused borders, active indicators, brand |
AccentAlt | Secondary accent | Alternating highlights, agent labels |
Green | Success / add | Success badges, diff additions, confirm buttons |
Red | Error / delete | Error text, diff deletions, reject buttons |
Yellow | Warning / caution | Warning text, tool calls, feedback buttons |
Blue | Info / brand | Brand glyph, directory names, info indicators |
Magenta | Accent secondary | Agent kind labels, alternate highlights |
Cyan | Code / inline | Inline code, code blocks, search highlights |
BorderNormal | Default borders | Pane borders, dividers, separators |
BorderFocused | Focused borders | Active pane, focused input, palette border |
color.Color (Go's image/color) for all slots, supporting truecolor, 256-color, and 16-color terminal palettes. The themes.Mix() function blends colors linearly, and themes.Luminance() / themes.IsDark() handle brightness detection for adaptive rendering.
Pre-built Lipgloss Styles
Each theme generates 50+ lipgloss styles via themes.NewStyles() in internal/tui/themes/theme.go:90. These cover every UI element:
Header,HeaderBrand,HeaderCenter,HeaderRight,HeaderPillStatusBar,StatusBarRightInput,InputFocusedPalette,PaletteItem,PaletteSelect,PaletteDim
UserMsg,UserLabel,UserBubbleAssistantMsg,AssistantLabel,AssistantBubbleToolCall,ToolResult,ToolBox,ToolNameToolHeader,ToolBody,ToolStatus,ToolDurationToolIcon,ToolAccent
ConfirmBox,ConfirmAllow,ConfirmAlways,ConfirmReject,ConfirmFeedbackDiffPane,DiffAction,ActivePane,InactivePaneFileTree,FileTreeDir,FileTreeFile,FileTreeSelectHelpBox
Base,Error,Border,Code,Dim,BoldSuccess,Warning,TimestampSystemMsg
Custom Themes via CreateCustomTheme()
You can create themes programmatically using themes.CreateCustomTheme():
// internal/tui/themes/engine.go:174
theme := themes.CreateCustomTheme("my-theme", map[string]string{
"background": "#1a1a2e",
"surface": "#16213e",
"overlay": "#0f3460",
"text": "#e6e6e6",
"subtext": "#b0b0b0",
"muted": "#808080",
"accent": "#e94560",
"accent_alt": "#533483",
"green": "#00b894",
"red": "#e94560",
"yellow": "#fdcb6e",
"blue": "#0984e3",
"magenta": "#6c5ce7",
"cyan": "#00cec9",
"border_normal": "#2d3436",
"border_focused": "#e94560",
})
engine.RegisterTheme(theme)
engine.SetTheme("my-theme")
Register the theme with the engine, and it becomes available in the /theme picker alongside all built-in themes.
Theme Gallery
All 11 built-in themes with their actual color palettes. Hover over any swatch to see its hex value.
Switching Themes
Interactive Theme Picker
/theme
Opens the Spotlight-style theme picker with a scrollable list of all registered themes. The currently active theme is marked with (current).
Direct Switch
/theme catppuccin
/theme dracula
/theme high-contrast
Switches to the named theme immediately. All UI elements repaint in one frame. The engine rebuilds every lipgloss style, markdown renderer, and diff palette from the new color slots.
Keyboard Navigation in Theme Picker
| Key | Action |
|---|---|
| ↑ k | Move selection up |
| ↓ j Tab | Move selection down |
| Enter | Apply selected theme |
| Esc | Cancel and close picker |
| Ctrl+Tab | Jump to next section (in palette categories) |
ThemeEngine.SetTheme() method accepts a name string and returns a boolean. Call CycleTheme() to iterate through all themes. Use OnThemeChange() to register listeners that fire on every switch.
TUI Layout
The Automergent TUI is a full-screen terminal application built with Bubble Tea. Every element adapts to the active theme:
Header Bar
The floating pill header displays at the top, showing:
- Brand mark — the
✦glyph in theme's Blue color, followed byAUTOMERGENT - Model & provider — current model name and provider icon
- Cost — session cost in USD ($0.00 format)
- Token meter — context usage bar (current tokens / max window)
- Git branch — active branch name from the working directory
- Phase pill —
init,explore,plan, orbuild(color-coded) - Effort — thinking effort level:
low,medium,high,max
Conversation Area
The main scrollable region displays the conversation as styled message bubbles:
- User messages — right-aligned with
UserBubble(Surface bg, Text fg) andUserLabel - Assistant messages — left-aligned with markdown rendering (glamour) using theme-derived syntax highlighting
- Tool cards — inline cards rendered by per-family renderers (see Tool Card Rendering)
- System messages — italic, Muted color
Input Area
A thin border-topped text input sits below the conversation. Displays:
- Approval mode indicator —
manual,accept-edits,auto, orplan(shown in status bar) - Context-aware hints — dynamic keybinding hints above the input change based on state (idle, running, palette open)
- Queue strip — when messages are queued, a strip shows them with Ctrl+X drop / Ctrl+O edit controls
Bottom Dock
The dock sits below the status bar and shows running background processes:
- Background shells — one row per running command with live status glyph
- Sub-agents — one row per spawned agent with kind label and progress
- Status marks —
✓success,✗failure,●running,◌idle - Collapse — dock collapses to a single line when empty; expands automatically on activity
Status Bar
The bottom bar shows the current state with independent slots:
- Mode chip — colored approval mode indicator (
MANUAL,ACCEPT EDITS, etc.) - Activity — transient status:
thinking…,▸ read_file…,retrying (3/10) - Outcome — sticky result:
CANCELLED,ERROR - HUD segments — context usage bar (
ctx 12% ##──────), git branch, pending edits count, problems count - Work dir —
~-abbreviated project path on the left edge - Clock — user's local time, auto-detected from IP
Diff Pane
Toggle with Ctrl+D or /diff. Shows a file-tabbed diff view of all edits made this session:
- File tabs — one tab per modified file with status icon
- Inline diffs — theme-colored additions (
Greenbg tint) and deletions (Redbg tint) - Word-level diffs — highlighted within changed lines using
Mix()blends - Navigation — ↑/↓ or j/k to move between files, Esc to close
File Tree Sidebar
Toggle with Ctrl+T or /tree (alias /files). Displays a navigable project file tree:
- Directories —
FileTreeDirstyle (Blue, bold) - Files —
FileTreeFilestyle (Text color) - Selection —
FileTreeSelecthighlight (Surface bg, Accent fg) - Navigable — arrow keys to move, Enter to open in diff pane or insert path
Command Palette
Spotlight-style command palette, opened with Ctrl+P or by typing / in the input:
- Fuzzy search — type to filter all commands, themes, and keybinding schemes
- Section jumps — Shift+Tab / Ctrl+Tab to jump between categories
- Sub-palettes — commands like
/themeand/keybindingsopen dedicated sub-palettes with their own items - Command hints — each item shows its icon, label, and description in a dim color
- Current indicator — active theme/keybinding/model marked with (current)
Tool Card Rendering
Every tool call is rendered as a compact card in the conversation area. Automergent uses per-family renderers that collapse verbose output into scannable one-liners:
tool_read.go · tool_edit.go · tool_terminal.go · tool_box.go · tool_web.go · tool_agent.go · tool_inspect.go
Read Cards (tool_read.go)
Reads are always one line, even for 500-line files. What matters is which file and how much, not the contents:
● Read internal/tui/components/tool_box.go · L40–160 · 121 lines 12ms
● Read src/main.rs · L1→ · 45 lines 8ms
● List internal/tui/components/ · 24 entries 3ms
● Grep "TODO|FIXME" · 14 matches across 6 files 22ms
The call line carries chips for the line range (L40–160), line count, and duration. Errors show the first line of error text as a chip.
Edit Cards (tool_edit.go)
Edits expand to show the diff — vertical space is always worth spending here:
● Edit handler.go · 1 line replaced 8ms
+1 −1 ──────────────────────────────────────────
34 │ limit := c.tailLimit()
35 │ limit := c.tailLimit() + 2
↑ first 3 hidden · ctrl+e expands
Diff boxes use theme-derived colors: additions get a Green-tinted background, deletions get Red-tinted. Word-level changes are highlighted within lines using Mix() blends at higher saturation.
Terminal Cards (tool_terminal.go)
Terminal output shows a themed slab (Surface background) with the command and merged output tail:
● Bash ───────────────────────────────────── ✓ exit 0 2s
$ go test ./internal/auth/...
ok github.com/.../auth 0.847s
The command appears once on the $ row. Stderr sections and failure preambles are stripped since the exit-chip already conveys the result. Running commands show ◌ running… and expand as output arrives.
Tool Card Anatomy
| Element | Style | Description |
|---|---|---|
| Glyph | statusGlyph() | ● success, ● error, ● running, ◌ pending |
| Name | ToolName | Bold text in tool's accent color |
| Subject | Dim | File path, command, or search pattern |
| Chips | Dim | Metadata: line ranges, line counts, exit codes |
| Duration | ToolDuration | Muted italic, right-aligned |
| Body | ToolBox | Surface-bg panel with diff, output, or error |
| Expand hint | Dim | ctrl+e expands when output is truncated |
Keyboard Shortcuts
Automergent supports three keybinding schemes. Switch with /keybindings or /keys:
Default Scheme
| Key | Action |
|---|---|
| Enter | Submit message |
| Ctrl+C | Quit (press twice to force exit) |
| Ctrl+Q | Quit (alias) |
| Esc | Cancel / interrupt / close overlay |
| Ctrl+D | Toggle diff pane |
| Ctrl+L | Toggle LSP integration |
| Ctrl+S | Open session list |
| Ctrl+N | New session |
| Ctrl+U | Clear input |
| ↑ / k | Scroll up |
| ↓ / j | Scroll down |
| PgUp | Page up |
| PgDn | Page down |
| Ctrl+J | Send after current tool / steer at tool boundary |
| Ctrl+P | Open command palette |
| Ctrl+T | Toggle file tree |
| Ctrl+W | Toggle diff pane (alias) |
| Ctrl+E | Expand truncated tool output |
| Ctrl+R | Toggle review mode / inline rename |
| Ctrl+X | Drop queued message |
| Ctrl+O | Pull queued message back into input |
| Shift+↑/↓ | Select in queue strip |
| Y / N | Confirm / deny in approval dialogs |
Vim Scheme
| Key | Differs from Default |
|---|---|
| k | Scroll up (primary) |
| j | Scroll down (primary) |
| Ctrl+U | Page up |
| Ctrl+D | Page down |
| q | Quit (alongside Ctrl+C) |
| Esc | Cancel (same as default) |
Emacs Scheme
| Key | Differs from Default |
|---|---|
| Ctrl+P | Scroll up (primary) |
| Ctrl+N | Scroll down (primary) |
| Alt+V | Page up |
| Ctrl+V | Page down |
| Ctrl+K | Clear input |
| Ctrl+G | Cancel (primary) |
Switching Schemes
/keybindings default
/keybindings vim
/keybindings emacs
Or open the sub-palette with /keybindings (no args) and select interactively.
Notification System
Automergent delivers notifications through multiple channels, configured in config.yaml:
notifications:
desktop: true # OS-level desktop notifications
bell: true # Terminal bell (\a) on completion
contextWarning: true # Warning when context window is nearly full
Desktop Notifications
When desktop: true, Automergent sends OS-level notifications via the terminal's notification protocol. Triggered when:
- A background shell completes or fails
- A sub-agent finishes its task
- The context window reaches a critical threshold
- A session requires user interaction after being idle
Terminal Bell
When bell: true, a \a (BEL) character is emitted for:
- Tool completion requiring approval
- Error conditions that need attention
- Background process state changes
Context Warnings
When contextWarning: true, the system warns before the context window fills up:
- 80% usage — info-level toast: "Context 80% full — consider compacting"
- 90% usage — warning toast: "Context nearly full — auto-compact will trigger"
- Auto-compact — automatic summarization when the threshold is reached
- Blocking limit — new messages are blocked until compaction completes
Toast Stack
In-app notifications appear as toast cards above the status bar:
- Max 3 visible — oldest evicted when exceeding the cap
- Auto-expire — 6 second TTL, then fade out
- Levels —
info(accent border),warn(yellow border),error(red border) - Fallback — when toast stack is unavailable, messages go to the status bar
Background Task Notifications
Both shell and agent managers emit completion hooks wired in notifications.go:
// Shell completion → toast
shellNotificationMsg{
id: "sh-001",
command: "go test ./...",
status: "success",
exitCode: 0,
duration: 2.3s,
}
// Agent completion → toast
agentNotificationMsg{
id: "agent-042",
name: "refactor-auth",
kind: "sub-agent",
status: "success",
summary: "Refactored 3 files, added JWT validation",
duration: 45s,
}