ox ships one palette in two variants. Every command — boxes, timelines, spinners, the doctor wordmark — uses the same semantic tokens; lipgloss picks the right hex at runtime based on your terminal's background.
How detection works
OSC 11 query. At first render, lipgloss queries the terminal for its actual background color (escape sequence \x1b]11;?\x07). Modern terminals (iTerm2, Alacritty, Kitty, Wezterm, Windows Terminal, recent VS Code) answer back; lipgloss computes luminance and picks dark or light.
COLORFGBG fallback. Some emulators (rxvt-derived) export this env var instead. lipgloss reads it.
Default dark. If nothing answers (CI, piped output, exotic terminal), ox assumes a dark background — the most common case among coworkers.
NO_COLOR=1 short-circuits everything: no ANSI emitted, terminal default colors only.
Rendering structured slog output for humans without giving up grep. Levels get colored, timestamps compacted, key=value pairs preserved. Pipe daemon logs through it.
Avoid when
JSON-mode output (`--json`) or anything that downstream tooling parses. Pretty-printing breaks aggregators.
markdown
data-display
Package
internal/ui
Exports
RenderMarkdown
Since
0.5.0
Use when
Long-form content with structure — release notes, agent responses, knowledge bubble snippets. Glamour-backed with a SageOx-tuned theme so output matches brand.
Avoid when
Short status output (markdown headers are overkill) or any performance-sensitive hot path — glamour parsing has measurable cost.
timeline
data-display
Package
internal/ui
Exports
RenderTimeline · TimelineNode · TimelineItem
Since
0.5.0
Use when
Multi-step output where order matters — doctor results, sync stages, post-install steps. Each node anchors a phase, items inside report findings.
Avoid when
Single-line status (use `StyleSuccess` directly) or tabular history (use Columns). Timelines are vertical; horizontal scans want tables.
spinner
feedback
Package
internal/cli
Exports
WithSpinner · WithSpinnerNoResult
Since
0.3.0
Use when
Wrap any operation expected to take > 300ms (network, git clone, daemon RPC). Auto-hides if the work completes faster, so fast paths don't flicker.
Avoid when
Operations < 100ms — the spinner appears, blinks, vanishes, and adds noise without value. Also: anything in a non-TTY (the spinner falls back silently, which is correct).
status-bar
feedback
Package
internal/dashboard/panes/statusbar
Exports
Pane · View
Since
0.7.0
Use when
Bottom row of full-screen TUIs. Left side carries persistent state (daemon health, open issues); right side carries the active hint ("? for help", "esc to cancel"). Transient toasts ("copied!") replace the right side for ~2s.
Avoid when
Inline commands — the bar wants a fixed-position last row, which only full-screen bubbletea programs offer. Don't fake it.
Yes/no gates with a clear default. For destructive operations use ConfirmDangerousOperation — it requires typing the exact target name, not just pressing y.
Avoid when
Selecting between equal options (use Select) or any flow where users will reflexively press enter — defaulting to dangerous is a footgun.
filter-tabs
input
Package
internal/dashboard/panes/timeline
Exports
renderFilterBar (private)
Since
0.7.0
Use when
A narrow numbered tab row at the top of a content pane — quick single-key switching between views of the same data (timeline filters, section selectors, log-level filters). Number keys 1–9 jump tabs; `/` opens an inline search line below.
Avoid when
More than ~6 tabs (the number-key shortcut breaks down). Selecting between entire screens — use the dashboard's section tabs instead.
multi-select
input
Package
internal/cli
Exports
SelectMany · MultiSelectOption
Since
0.4.0
Use when
Pick zero-or-more from a known set — `ox init` agent-hook installation, multi-team enablement, feature opt-ins. Renders as a checkbox group; space toggles, enter confirms.
Avoid when
Exactly-one selection (use Select for radio-style). Free text (use Prompt). Sets larger than ~15 items — paginate or filter.
prompt
input
Package
internal/cli
Exports
SelectOne
Since
0.3.0
Use when
Free-form text input with a default suggestion. Reads from stdin in non-TTY mode without changing the contract — so prompts compose with `echo X | ox foo` cleanly.
Avoid when
Sensitive input (no echo masking yet — file an issue) or structured data better served by flags.
select
input
Package
internal/cli
Exports
SelectOne · SelectOneValue · SelectMany
Since
0.4.0
Use when
Radio-button single-pick from a known set of options — `ox init` endpoint picker, team chooser, IDE selector. Arrow-key navigation in TTY; numbered-prompt fallback in pipes and CI. Generic SelectOneValue avoids index-juggling.
Avoid when
Multi-select (use multi-select / SelectMany — the checkbox cousin). Free-form text (use Prompt) or yes/no (use Confirm). Lists longer than ~20 items — paginate or filter at the caller level first.
box
layout
Package
internal/ui
Exports
RenderBox · RenderSummaryBox · BoxVariant
Since
0.4.0
Use when
Group a small payload (a tip, a callout, a summary) that benefits from a visible boundary. Variants color the border by intent (info/warn/error/success).
Avoid when
Wrapping long-form output — boxes around paragraphs add cost without information. For multi-step results use a Timeline instead.
columns
layout
Package
internal/cli
Exports
ColumnWidths · FormatRow
Since
0.4.0
Use when
Aligned tabular output where columns share semantic meaning across rows (session lists, team rosters, sync state). Widths auto-compute from content with min/max clamps.
Avoid when
Single-row key=value displays (use log-formatter) or content that can't survive truncation on narrow terminals — design column widths around 80 columns.
modal
layout
Package
internal/dashboard/overlays
Exports
Overlay · OverlayConfirm
Since
0.7.0
Use when
Floating dialogs inside a full-screen TUI: help (?), command palette (Ctrl+K), confirmation gates. Consumes all keys until dismissed. Backdrop dims the underlying surface so focus is obvious.
Avoid when
One-shot commands — no underlying TUI to overlay. Use a Box or ConfirmDangerousOperation prompt instead.
nav-tree
layout
Package
internal/dashboard/panes/nav
Exports
Pane · View
Since
0.7.0
Use when
Left-rail navigation in full-screen TUIs — workspaces, teams, sessions, recent activity. Hierarchical with collapse/expand. Selected row gets a bold inverted highlight; section headers in secondary color.
Avoid when
Flat lists fit better in Columns. Trees deeper than 3 levels become a navigation problem of their own — paginate or filter first.
pane
layout
Package
internal/dashboard/theme
Exports
PaneBorderFocused · PaneBorderUnfocused
Since
0.7.0
Use when
Full-screen TUIs that split work across regions (dashboard, config-tui). The focused pane gets a double border in brand primary; unfocused panes use a rounded border in dim. Tab swaps focus.
Avoid when
One-shot command output — a bordered region just steals vertical space. Use Box for static callouts instead.
wordmark
layout
Package
internal/ui
Exports
RenderWordmark · WriteWordmark
Since
0.4.0
Use when
Branded headers for commands that own a moment — `ox doctor`, `ox init` success, release-notes banners. Two-tone color (Sage/Ox) keys the wordmark to the brand palette.
Avoid when
Routine command output. The wordmark earns its vertical space only when the command is a destination, not a step in a pipeline.
config-screen
screen
Package
cmd/ox/config_tui.go
Exports
configModel
Since
0.6.0
Use when
The full `ox config` TUI surface: a rounded-bordered frame with an overlaid title, categorized settings list, cursor-driven selection, value column with source-precedence arrows, and a help footer. This is the canonical example of an interactive ox screen.
Avoid when
Inline commands — the frame and per-row source arrows assume a controlled full-screen surface. Don't fake the chrome in scrollable output.
dashboard-screen
screen
Package
internal/dashboard/app
Exports
Model
Since
0.7.0
Use when
Reference for any new full-screen bubbletea program in ox. Shows how Nav · Timeline · Inspector · StatusBar compose; how focused vs unfocused panes signal attention; how a Tab/section navigator anchors orientation.
Avoid when
Inline commands. The four-pane layout assumes 80×24 minimum and a controlled alternate screen — don't fake the chrome inline.
The canonical "destination command" composition: branded wordmark + categorized check timeline + closing summary box. Reference this shape for any command the user runs to *resolve* something, not just describe it.
Avoid when
Pipeline commands — the wordmark earns its vertical space only when the command is a destination. Don't print it from automation paths.
login-screen
screen
Package
cmd/ox/login.go
Exports
loginSpinnerModel
Since
0.3.0
Use when
The smallest possible full-screen bubbletea program in ox: one spinner, one message line, one Ctrl+C handler. Use this as the reference for any "wait for external thing" screen (OAuth callback, daemon handshake).
Avoid when
Foreground operations whose duration is bounded and predictable — use the inline Spinner component instead. The full-screen treatment is reserved for genuinely open-ended waits where Ctrl+C is the user's only out.
session-list-screen
screen
Package
cmd/ox/session_list.go
Exports
runSessionList
Since
0.5.0
Use when
List view with session-specific badges — hydration state, duration coloring, type indicator. Reference for any per-row list where each row has a status that the user might filter or sort by.
Avoid when
Generic tabular data — use Columns. Multi-line per-row content — use Timeline with one Node per row.
status-screen
screen
Package
cmd/ox/status.go
Exports
renderTable
Since
0.4.0
Use when
Tufte-minimal section-table pattern used by `ox status`, `ox teams`, `ox murmur status`. Bold-secondary section header, dim left-column labels, semantic-colored values, no decorative borders. Reach for this shape any time you have grouped key/value facts to display.
Avoid when
Truly tabular data with > 3 columns — use Columns. Long-form or hierarchical state — use Timeline.
sparkline
viz
Package
internal/tui
Exports
RenderSparkline · RenderSparklineTimeMarkers
Since
0.6.0
Use when
Compact activity-over-time visualization in a single line. Default window is 4 hours bucketed into 5-minute slots — perfect for session-cadence and sync-frequency views.
Avoid when
Precise numerical readouts (use a table) or windows longer than a few hours where 5-minute buckets blur the signal.