Source of truth for the ReverbCode desktop UI (Electron + React 19 + Tailwind v4
- Radix/shadcn + xterm, in
frontend/src/renderer). Read this before any visual or UI change. Created by/design-consultationon 2026-06-09.
By explicit user decision (2026-06-10), the renderer clones the agent-orchestrator web app verbatim in looks and design. This supersedes the "match emdash" direction documented in Aesthetic Direction and the palette sections below — where they conflict, agent-orchestrator wins. Do not re-flag "this doesn't match emdash" in QA/review; flag divergence from agent-orchestrator.
- Reference (the user's own app):
~/Projects/agent-orchestrator/packages/web/src—app/globals.css,app/mc-board.css,app/mc-sidebar.css,components/{ProjectSidebar,Dashboard,SessionCard,SessionDetailHeader,SessionInspector,StatusBadge}.tsx. - Palette (live in
frontend/src/renderer/styles.css:root):--bg #0a0b0d,--bg-1 #15171b,--fg #f4f5f7,--fg-muted #9ba1aa,--fg-passive #646a73, hairline white-alpha borders, accent--accent #4d8dff; status: working=orange#f59f4c, needs-you=amber#e8c14a, mergeable=green#74b98a, fail=red#ef6b6b. The sidebar rail is the cooler#08090b. - Cloned surfaces: the four-column gradient kanban board, the
ProjectSidebar(brand + project disclosure + nested session rows + Settings menu footer), the session topbar (Kanban back button + identity + breathingStatusBadgepill), and the sharedDashboardTopbar/DashboardSubheadchrome (Coding/Reviews tabs · "N working" pill · subhead) reused across board/review/PR/settings. - Build with shadcn primitives where a component fits (
components/ui/*: dropdown-menu, select, card, table, tooltip, …); agent-orchestrator's own hand-rolled CSS components are structure/behaviour reference only. - The one carried-over divergence still holds: the accent is refined blue, and the terminal keeps its own palette. Everything else tracks agent-orchestrator.
- Approved divergence (2026-06-10): on macOS, a titlebar cluster (sidebar toggle +
back/forward history arrows,
TitlebarNav) sits beside the traffic lights, VS Code-style — the web reference has no window chrome, so no analogue exists. - Approved divergence (2026-06-10): the session inspector rail is fully
collapsible, built on the shadcn resizable primitive (
pnpm dlx shadcn add resizable, react-resizable-panels v4collapsiblepanel + imperative API, user-requested). The panel animates to 0% via a flex-grow transition while the content keeps a stable min-width (yyork-style, no mid-animation reflow). Toggled by aPanelRighticon button in the session topbar and ⌘⇧B; open state + split width persist. The AO reference keeps the rail always visible. - Approved divergence (2026-06-12): the shell topbar spans the full window
width and the sidebar is pinned below it (
top-14), so the sidebar's right border stops at the header instead of cutting through the macOS traffic-light strip (user-requested). The AO reference keeps a full-height sidebar with the header beside it. On macOS the header always pads past the lights + TitlebarNav cluster (.is-under-titlebar-nav, 180px).
- What this is: ReverbCode is an Electron desktop app for supervising many parallel
AI coding-agent sessions, backed by a Go daemon (
backend/). TheaoCLI is the thin client over the same daemon. - Who it's for: professional software engineers running multiple coding agents at once who need to delegate, watch, intervene, and ship PRs.
- Space/peers: agent orchestration / parallel-agent desktop tools. Closest peers: emdash (the primary design reference), PostHog Code, Conductor.
- Project type: dark-mode-primary desktop app; terminal-dense; keyboard-driven; runs all day.
- The one memorable thing: leverage and speed — "I'm more in control here than babysitting N terminal tabs myself."
ReverbCode is orchestrator-led, which is the one thing that differs from emdash
(a flat list of independent sessions). Grounded in the daemon
(backend/internal/session_manager/manager.go, docs/architecture.md):
- A Project is a registered git repo.
- Per project there is one active Orchestrator session plus N Worker sessions.
Both are the same underlying "session" (durable facts:
activity_state,is_terminated, PR facts); they differ only byKind(KindOrchestratorvs the default worker). A project may run the orchestrator on a different agent than its workers. - The Orchestrator is the human-facing coordinator: you talk to it; it spawns
workers (
ao spawn), messages them (ao send), tracks progress, and synthesizes results. It avoids implementing unless necessary. - A Worker is a normal agent session — nothing special-cased. It runs one focused task in an isolated git worktree + branch, with the agent CLI in a terminal as the conversation, producing a diff → commit/push → PR. It escalates to the orchestrator only for true blockers or cross-session coordination.
- The daemon observes runtime + PR/CI/review facts and derives display status
at read time:
working,needs_input,ci_failed,changes_requested,mergeable,approved,review_pending,pr_open,idle,terminated,merged. Never store display status; keep session facts small.
Superseded (2026-06-10): see the Design direction — clone agent-orchestrator verbatim banner at the top. The emdash framing below is retained for history; the live look tracks agent-orchestrator (same flat near-black / hairline family, so most of this still reads true).
- Direction: match emdash exactly — flat, near-black, hairline-bordered, utilitarian. Industrial control surface, calm chrome, the terminal as the center of gravity.
- Decoration level: minimal. Type + 1px hairlines do all the work. No gradients, glow, blobs, or emoji.
- Mood: low-glare, dense, keyboard-native; signal-over-noise.
- Reference: emdash (primary, visual +
structural), PostHog Code (secondary). Tokens
below were extracted from emdash's
src/renderer/index.css. - Deliberate tradeoff: to be emdash, we use the system font stack (not a custom typeface) and emdash's neutral palette. We diverge in exactly one place: the accent is ReverbCode's refined blue, not emdash's jade green. The terminal keeps green (it is the agent CLI).
System fonts only, like emdash — no custom/Google fonts, zero font payload.
- UI / body / display:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Helvetica Neue", sans-serif(San Francisco on macOS). - Mono / terminal / code / eyebrow labels:
Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace. - Eyebrow labels (section titles, dialog titles, the rail "PROJECTS" header):
mono, uppercase,
letter-spacing: .12–.14em,--foreground-passive. - Scale: 14px base UI / sidebar (
text-sm, weight 400) · 12px secondary + labels (text-xs) · 13px code/mono/terminal · 11px tiny · 10px micro + badges · 9px sidebar badge label. Buttons arefont-normal(400), not bold.
emdash's flat Radix-neutral near-black ramp carries the whole interface; color is rare
and meaningful. Values are sRGB approximations of emdash's color(display-p3 …) tokens.
| Role | Hex |
|---|---|
--bg canvas |
#111111 |
--bg-1 surface |
#191919 |
--bg-2 raised / hover / active row |
#222222 |
--bg-3 |
#2a2a2a |
--fg text |
#eeeeee |
--fg-muted |
#b4b4b4 |
--fg-passive |
#6e6e6e |
--border hairline |
#3a3a3a |
--border-1 |
#484848 |
--accent (blue) |
#5b9dff |
--needs-you / in-progress (amber) |
#ffcc4a |
--success / mergeable (green) |
#6cb16c |
| terminal green | #7bd88f |
--error (red) |
#d4544f |
| text selection | #3f8ef7 @ 35% |
| terminal bg | #161616 |
| Role | Hex |
|---|---|
| canvas / surface / raised | #fcfcfc / #ffffff / #ededee |
| text / muted / passive | #1a1a1a / #666666 / #9a9a9a |
| border | #e3e3e5 |
| accent (blue) | #2563eb |
| amber / green / red | #9a6b00 / #1a7f37 / #c0392b |
- Blue = the live edge only: primary buttons, the active/selected session, focus rings. Never decorative.
- Amber = an agent needs you (blocked /
needs_input/review_pending). - Green =
mergeable/success and terminal/agent CLI text. - Red =
ci_failed/ destructive. - These map 1:1 to the daemon's derived statuses.
Session status is a single ~14px glyph in one fixed slot, never a text pill/badge:
- Working / active → an animated spinner (accent).
- Has an open PR → a PR icon, tinted by PR state: mergeable/approved green,
ci_failedred, review/changes_requestedamber, plainpr_openmuted. - Otherwise → a filled dot:
needs_inputamber (pulsing), idle/done muted gray.
Precedence: working spinner > PR icon > dot. Implemented as StatusGlyph in
components/SideRail.tsx; used in the orchestrator's Workers list. (Worker rows in the
left rail stay name-only — no glyph.)
- Base unit: 4px (Tailwind scale: 1=4, 1.5=6, 2=8, 3=12, 4=16, 5=20, 6=24).
- Density: compact / desktop-tight.
- Control + row height:
h-8= 32px default;h-7= 28px small;h-6= 24px xs. - Inputs
px-2.5 py-1; buttonspx-2.5, gap 1–1.5.
- Approach: fixed three-pane app shell, opens into the workbench (no marketing/dashboard home).
- Panes:
[ rail 240px ] [ center 1fr ] [ side rail 316px ]. - Rail (240px), top → bottom:
- Orchestrator anchor — pinned, single, visually distinct (blue 2px left bar,
--bg-2fill, hub/waypointsicon, name "Orchestrator", a5 agents · 2 need youmono summary). This is ReverbCode's one addition over emdash. Default landing view. PROJECTSeyebrow label + a+.- Project rows (folder icon + name) with nested worker rows beneath. Each project
row has a hover-revealed
+that opens the New-worker modal pre-scoped to that project (distinct from thePROJECTSheader+, which registers a repo). - Footer:
Search ⌘K,Settings ⌘,. (No Library.) - Account row pinned at the very bottom.
- Orchestrator anchor — pinned, single, visually distinct (blue 2px left bar,
- Worker rows are name-only. Just the session name, truncated. Status, branch, diff,
and PR live in the panes and topbar, never in the row. Selection =
--bg-2fill + a 2px blue left bar. (emdash itself shows a faint trailing timestamp; we omit it by choice.) - Center = the conversation. Orchestrator → its coordination terminal (delegate here;
composer reads "tell the orchestrator what to build"). Worker → the agent CLI terminal
(tabbed per agent, e.g.
claude-code (1)), with a composer (model selector, worktree path,Accept edits). The terminal is the conversation; no separate chat surface. - Side rail (316px): orchestrator → a quiet Workers list (name + project + derived
status). Worker → the Git review rail:
Changed N→ All files / Discard all / Stage all → file rows (+adds −dels, stage toggle) →Commit message+Description→ Commit & Push (primary blue) → branch +Create PR. - Border radius:
sm4px (scrollbar) ·md6px (buttons, inputs, toggles) ·lg8px (rows, cards, panels) ·xl12px (modals) ·full(badges/pills/dots). - Icons: lucide only. No emoji.
- Left (both):
project / sessionbreadcrumb + pin; for the orchestrator, a hub iconOrchestrator.
- Right — worker session: a PR/CI status pill that is the action
(
PR #156 · mergeablegreen /CI failedred /review requestedamber /Open PRwhen none) → Changes / Files / Terminal view toggles → ⋯ session menu (rename, restart, kill, claim PR — theao session …commands). - Right — orchestrator: + New worker → Terminal toggle → ⋯ menu. No diff toggles.
You mostly let the orchestrator spawn workers from its conversation; the manual paths
(the topbar + New worker, a project row's hover +, or ao spawn) open a modal that
mirrors emdash exactly. Launching from a project row pre-fills the Project field:
- Centered dialog, 12px radius,
max-w~512px,bgcanvas,ring-1at 10% fg, fade + zoom-95 enter. - Header: eyebrow mono-uppercase title
New worker+×close. - Body (
gap15–16px): a borderless large name field (18px, auto-focus, slug rule "letters, numbers, hyphens") → Project selector → Agent selector (claude-code / codex / opencode / …) → a "Based on" bordered card with a segmented controlBranch · Issue · Pull Requestrevealing a combobox → a Prompt / Workspace tab where Prompt is the worker's initial task (textarea). - Footer: right-aligned single primary
Spawn worker(blue) with a⌘↵keycap, disabled until valid.
- Approach: minimal-functional. The one expressive exception: a status dot/spinner pulse on active/working sessions (opacity breathe) so "alive" is glanceable. Never animate text or layout.
- Easing: enter
ease-out, exitease-in, moveease-in-out. - Duration: micro 80ms · short 160ms · medium 240ms · status pulse 1.8s loop · modal enter ~150ms fade+zoom-95.
- The renderer (
frontend/src/renderer/styles.css) currently uses Inter and a grayscale-blue theme. Migrate to this system: drop the Interfont-family, adopt the system stack, and replace the token values with the emdash neutral ramp + blue accent above. - Keep tokens as CSS custom properties under
:root(dark) and:root[data-theme="light"]. - A faithful HTML reference of all of the above (both views + topbar + spawn modal,
light/dark) is saved under
~/.gstack/projects/aoagents-agent-orchestrator/designs/design-system-20260609/.
| Date | Decision | Rationale |
|---|---|---|
| 2026-06-09 | Match emdash's visual language exactly | User direction; emdash is the demonstrated reference for this app's UI. |
| 2026-06-09 | System font, not a custom typeface (e.g. Geist) | emdash uses the system stack; fidelity + native feel + zero font payload chosen over brand type. |
| 2026-06-09 | Refined blue accent, not emdash's jade green | User's explicit pick; blue for primary/active/focus, terminal stays green. |
| 2026-06-09 | Single global Orchestrator anchor, orchestrator-first default view | The one real difference from emdash; orchestrator is the human-facing coordinator you delegate to. |
| 2026-06-09 | Name-only worker rows | User direction; status/branch/diff live in panes + topbar, not the row. |
| 2026-06-09 | Removed Library from the rail footer | User direction; footer is Search + Settings only. |
| 2026-06-09 | Topbar right = PR/CI pill + view toggles + ⋯ menu (worker) | Surfaces the actionable PR/CI state from the daemon; emdash/PostHog Code precedent. |
| 2026-06-09 | Spawn modal mirrors emdash's Create Task | Consistency with the reference; mapped to ao spawn params. |