Arbiter TUI

Arbiter's interactive terminal interface. One process, one shell window — but inside that window: a multi-pane layout where each pane is an independent conversation with its own agent, history, and streaming output. The TUI is what you get when you run arbiter with no arguments.

Rendering uses OpenTUI (native cell-buffer diff renderer). Per-pane chrome, scrollback, and input are composited each frame by the output pump (~30 ms).

A pane is to a conversation what a tab is to a browser. A new pane is a new conversation against an agent of your choosing; multiple panes run side-by-side or stacked, each independently typing, streaming, and waiting for its agent. Background loops (long-running agent processes) live alongside; foreground panes can spawn child panes (/pane <agent> <msg>) whose results land back in the spawner when done.

Start with arbiter. The default layout is a single pane covering the main terminal area. A left-hand conversation sidebar lists prior threads and lets you start a new one (Ctrl-w b to enter, Ctrl-w t to toggle visibility). A right-hand sidebar shows session usage, agent/model, todos, and recent tool activity when the terminal is wide enough (MCP appears only after MCP tools are used); Ctrl-w s toggles it. Ctrl-w v / Ctrl-w h split the main area.

Screen anatomy

Every pane has the same chrome layout. From top to bottom:

┌──────────────────────────────────────────────────────────┐
│ agent · session title                       status/stats │  row 1: identity + status
│ ───────────────────────────────────────────────────────  │  row 2: header separator
│                                                          │
│   streamed model output, tool-call summaries, /cmd       │  scroll region
│   results, system messages …                             │  (scrolls; bounded ring)
│                                                          │
│ ─── [⠋ 3 tool calls…] ──────────────────────────────────  │  mid separator
│ ❯ user input here, multi-line if it wraps                │  input area (1..5 rows)
│ ─────────────────────────────────────────────────────── │  hint separator
│ esc interrupt · pgup/dn scroll · /agents · /help         │  hint row
└──────────────────────────────────────────────────────────┘

What lives where:

  • Identity row. Left side: focused agent name and the session title. Right side: live status when the agent is working ("thinking…"), or aggregate token / cost stats when idle.
  • Header separator. Plain dashed line; gets an accent colour on the focused pane in multi-pane layouts.
  • Scroll region. Where everything the agent emits goes — streamed prose, tool-call summary lines, /cmd output, system notices. Scrollable with PgUp/PgDn (virtual-line aware: wrapped lines count as multiple rows). Markdown/theme ANSI is rendered as OpenTUI syntax highlights.
  • Mid separator. Dashed line above the input. Doubles as the tool-call indicator: while a turn is firing tool calls, this row shows ⠋ N tool calls… instead of plain dashes.
  • Input area. 1 row by default, grows up to 5 as text wraps. Standard editing controls (arrows, history, tab-complete on slash commands). Rendered by OpenTUI EditBuffer / EditorView.
  • Hint row. Static legend of the most-used keys and commands. In multi-pane layouts the compact chord hint (^W w/z/c) paints on the focused column's outer-bottom pane. Outer-bottom panes keep a shared footer pad so column bottoms stay aligned; stacked panes above that edge use a single-cell separator gutter (no trailing pad; output float only on outer-top). chrome_compact_rows reclaims pad only when show_footer is off.

When the terminal is at least 96 columns wide and only one pane is open, a fixed right column (~24–28 cols) shows live session telemetry after the first prompt is submitted (restored sessions with history show it immediately). The sidebar hides automatically below 96 columns, when a second pane is split open, or when toggled off with Ctrl-w s.

  • Context — context window fill (used % and token fraction from the last turn; session peak %), plus cumulative in/out tokens, cost, and turn count.
  • Agent — focused pane's current agent and model; last turn model when different.
  • Task — focused pane's pinned original task (advisor-gated work).
  • Todos — open /todo items tracked this session (when present).
  • Scheduled/schedule entries and active /loop background tasks (when present).
  • Tools — recent tool calls with descriptive labels (exec: git status, write: path, …) and ✓/✗ status; live count while a turn runs tools.
  • MCP — recent MCP invocations as server.tool, listed separately.

Token totals also appear in the pane header stats row (right side of row 1) when idle. /tokens prints the full breakdown in scrollback.

Where to next

  • Slash commands — the full /cmd catalogue, grouped by category.
  • Keybindings — every key, chord, and modifier the editor recognizes.
  • Panes — multi-pane layouts: split, focus, close, /pane spawn semantics.
  • Streaming — what you see during a turn: thinking spinner, tool-call indicator, verbose mode, cancellation.
  • Sessions — global conversations, autosave / mid-turn checkpoints, compaction.
  • Output UX — tool timeline, thinking rows, permission cards, replay chrome.
  • ThemesTuiDesign schema, theme tokens, and spacing.

Configuration

Per-user state lives under ~/.arbiter/:

PathWhat it is
openrouter_api_keyOpenRouter API key for hosted models.
agents/*.jsonAgent constitutions — one file per agent.
conversations/Legacy TUI JSON archive + layout.json mirror (sessions live in tenants.db).
tenants.dbTenant store: conversations (TUI + API), scratchpads, structured memory, schedules, todos, lessons (TUI and --api).
sessions/*.jsonLegacy per-cwd snapshots (imported once into the conversation store).
memory/t<tid>/Legacy filesystem scratchpad fallback (DB is primary).

Pane layout restores from tui_prefs / conversations/layout.json on relaunch (split tree + per-pane conversation bindings). Painted scrollback is rebuilt via transcript replay, not a pixel buffer; see Sessions.

TUI design config

Themes are JSON-driven. See TUI theme JSON for the full schema, export workflow, and custom theme files.

Summary:

  • ~/.arbiter/tui.json"preset": "nord" or "theme_file": "themes/mine.json", plus optional per-token overrides.
  • themes/*.json (in the repo; embedded into the binary at build time) — all built-in presets; also written to ~/.arbiter/themes/ on arbiter --init.
  • ~/.arbiter/themes/*.json — your custom themes or edited copies of built-ins.
  • arbiter --export-theme PRESET — dump a complete theme JSON to stdout (starter for editing).
  • /theme, /theme save, /theme file — browse with ↑↓ preview, export, or load themes in-session.

Built-in presets:

PresetCharacter
high-contrastDefault. High-contrast dark — white on black, saturated accents.
onedarkAtom OneDark — blue focus, warm code, green/red diffs.
modernNeutral black chrome with warm orange accent.
nordCool arctic blues and muted frost tones.
draculaPurple/pink/cyan on #282a36.
solarizedEthan Schoonover Solarized Dark.
lightLight background for bright terminals.
gruvboxWarm retro groove — orange/green on earthy browns.
catppuccinMocha pastels — lavender and pink on deep plum.
tokyo-nightNight city blues and soft purple accents.
monokaiClassic editor — yellow/green on olive black.
rose-pineMuted rose and iris on midnight violet.
ayuHigh-contrast dark — orange and cyan pops.
cobaltDeep navy chrome with electric blue focus.
everforestForest greens and soft sage on charcoal.
githubGitHub-dark neutrals with blue links.
palenightMaterial purple and soft blue-gray panels.
synthwaveNeon magenta and cyan on ultraviolet black.
zenburnLow-contrast olive-gray with sage accents.
solarized-lightSolarized Light — cream paper with teal/blue accents.
github-lightGitHub Light — white chrome, blue links, soft neutrals.
catppuccin-latteCatppuccin Latte — lavender pastels on soft paper.
gruvbox-lightGruvbox Light — warm parchment with earthy accents.
rose-pine-dawnRosé Pine Dawn — muted rose and iris on ivory.
one-lightAtom One Light — clean gray-white with blue focus.
papercolorPaperColor Light — high-legibility print palette.
flexoki-lightFlexoki Light — ink-on-paper with restrained hues.
high-contrast-lightHigh-contrast light — black text on white, vivid accents.
kanagawaKanagawa Wave — ink blacks with soft gold and sea blues.
oxocarbonOxocarbon — IBM Carbon blacks with neon pink/cyan.
night-owlNight Owl — deep navy with soft violet and mint.
horizonHorizon — warm rose accents on charcoal violet.
flexokiFlexoki Dark — near-black ink with earthy accents.
poimandresPoimandres — cool teal focus on midnight blue.
vesperVesper — minimal black with peach and mint accents.
moonlightMoonlight — soft indigo panels with pastel syntax.
materialMaterial Oceanic — blue-gray chrome, Material accents.
andromedaAndromeda — cyan/magenta pops on slate.
catppuccin-frappeCatppuccin Frappé — muted pastels on soft charcoal.
catppuccin-macchiatoCatppuccin Macchiato — balanced midnight pastels.
tokyo-night-stormTokyo Night Storm — stormier panels, same city blues.
tokyo-night-lightTokyo Night Light — day-mode blues on cool gray paper.
rose-pine-moonRosé Pine Moon — rose/iris on cooler violet night.
ayu-mirageAyu Mirage — warm gold focus on slate mirage.
ayu-lightAyu Light — orange/cyan pops on bright paper.
kanagawa-dragonKanagawa Dragon — ink blacks with muted gold.
kanagawa-lotusKanagawa Lotus — parchment with sea and plum accents.
everforest-lightEverforest Light — soft sage on cream paper.
papercolor-darkPaperColor Dark — high-legibility print on charcoal.
nightfoxNightfox — cool blue focus on deep navy.
dawnfoxDawnfox — Rosé Pine–adjacent dawn warm light.
dayfoxDayfox — bright warm light with bold accents.
duskfoxDuskfox — violet dusk with soft rose accents.
nordfoxNordfox — Nightfox × Nord arctic blues.
terafoxTerafox — teal earth tones on deep green-black.
carbonfoxCarbonfox — IBM Carbon blacks with neon accents.
icebergIceberg — cool blue-gray chrome, soft contrasts.
sonokaiSonokai — vivid Motoko accents on dark gray.
auraAura — purple/mint neon on near-black.
laserwaveLaserwave — magenta synthwave on violet black.
cyberdreamCyberdream — high-saturation neon on OLED black.
cyberdream-lightCyberdream Light — neon accents on white.
nightflyNightfly — deep navy with soft violet and mint.
moonflyMoonfly — near-black with bright pastel syntax.
jellybeansJellybeans — warm classic Vim palette.
apprenticeApprentice — low-contrast muted dark.
gothamGotham — teal-forward noir chrome.
srcerySrcery — high-contrast earth and crimson.
tenderTender — soft olive/cream accents on dark.
tomorrow-nightTomorrow Night — classic Base16 dark.
tomorrowTomorrow — classic Base16 light.
oceanic-nextOceanic Next — slate ocean with soft pastels.
shades-of-purpleShades of Purple — vivid purple chrome, neon pops.
cobalt2Cobalt2 — Wes Bos yellow focus on deep blue.
pandaPanda Syntax — pink/mint accents on charcoal.
noctisNoctis — cool teal focus on deep blue-green.
blulocoBluloco Dark — saturated workbench accents.
bluloco-lightBluloco Light — same accents on bright paper.
doom-oneDoom One — Emacs Doom dark, OneDark-adjacent.
doom-one-lightDoom One Light — Emacs Doom light variant.
modus-vivendiModus Vivendi — WCAG-oriented high-contrast dark.
modus-operandiModus Operandi — WCAG-oriented high-contrast light.
seoul256Seoul256 — low-contrast warm gray.
lucarioLucario — blue slate with purple/cyan pops.
miasmaMiasma — swampy olive/brown noir.
zenbonesZenbones — muted stone with soft rose accents.
fairy-flossFairy Floss — pastel candy on soft purple.
outrunOutrun — hot pink/cyan neon on deep purple.
monokai-proMonokai Pro — refined Monokai spectrum.
monokai-lightMonokai Light — classic Monokai on cream.
github-dimmedGitHub Dimmed — softer GitHub Dark neutrals.
quiet-lightQuiet Light — gentle gray-white workbench.
winter-is-comingWinter is Coming — icy blues on deep navy.
abyssAbyss — deep blue-black, restrained accents.
kimbie-darkKimbie Dark — warm brown with orange focus.
tomorrow-night-blueTomorrow Night Blue — bright pastels on navy.
tomorrow-night-brightTomorrow Night Bright — high-contrast on black.
spacegraySpacegray — cool gray chrome with soft blues.
paraiso-darkParaiso Dark — purple-brown Base16 dark.
paraiso-lightParaiso Light — purple-brown Base16 light.

Pick a preset in tui.json:

{
  "preset": "nord"
}

Export and customize:

arbiter --export-theme nord > ~/.arbiter/themes/my-nord.json

Then set "theme_file": "themes/my-nord.json" or edit colors inline — see TUI theme JSON.