agent-orchestrator/docs/design/design-brief.md

33 KiB
Raw Permalink Blame History

Agent Orchestrator Dashboard — Design Brief

Research-backed design specification for the ao dashboard
Version 2 — Updated with Playwright CSS extraction from live sites


Product Context

The Agent Orchestrator dashboard is mission control for parallel AI coding agents. Users are senior engineers and CTOs who routinely spawn 1030 agents at once and need to:

  1. Triage at a glance (who needs me right now?)
  2. Merge PRs that are ready
  3. Intervene on blocked or stuck agents
  4. Understand what each agent is doing without attaching to it

Primary interaction model: scan → identify → act. Not explore, not browse. The interface must surface actionable items immediately and suppress noise. Speed and density beat friendliness. This is closer to Grafana or an APM dashboard than to a product onboarding flow.


1. Competitive Visual Analysis

Linear (linear.app) — Ground truth via CSS extraction

Playwright was used to extract exact token values from the live site. See screenshots/linear-homepage.png.

Verified color palette:

  • Body background: rgb(8, 9, 10)#08090A — near-pure black with imperceptible warm cast
  • Product panel background: #0F1011 (CSS token --color-bg-panel)
  • Marketing background: #010102 (CSS token --color-bg-marketing)
  • Brand accent / link color: #7070FF (CSS token --color-accent, --color-brand-bg)
  • Focus ring: #5E6AD2 (CSS token --color-indigo)

Verified semantic status colors:

--color-blue:   #4EA7FC  (informational, active)
--color-red:    #EB5757  (error, critical)
--color-green:  #27A644  (success, done)
--color-orange: #FC7840  (warning, medium priority)
--color-yellow: #F0BF00  (caution, low priority)
--color-teal:   #00B8CC  (informational variant)
--color-indigo: #5E6AD2  (brand, focus ring)

Verified typography:

  • UI font: "Inter Variable" with "SF Pro Display" fallback
  • Monospace: "Berkeley Mono" — a premium licensed monospace, not JetBrains Mono as commonly assumed. Fallback: "SFMono Regular", Consolas, Menlo
  • Display/serif: "Tiempos Headline" — premium editorial serif (used sparingly for marketing copy)
  • Font weights (non-standard variable font values): light=300, normal=400, medium=510, semibold=590, bold=680

Verified type scale:

--text-tiny-size:    0.625rem  = 10px
--text-micro-size:   0.75rem   = 12px
--text-mini-size:    0.8125rem = 13px
--text-small-size:   0.875rem  = 14px
--text-regular-size: 0.9375rem = 15px
--text-large-size:   1.0625rem = 17px

Letter spacing: Negative tracking at most sizes (0.010em to 0.013em for body/mini). Titles use 0.022em at large sizes.

Verified spacing/radius:

--radius-4:  4px   (inputs, small badges)
--radius-6:  6px   (buttons, cards)
--radius-8:  8px   (modals, panels)
--radius-12: 12px  (larger surfaces)
--radius-16: 16px  (overlays)

Verified transitions:

--speed-quickTransition:   0.1s
--speed-regularTransition: 0.25s

Shadows: Zero visible shadows in dark mode (all --shadow-* = var(--shadow-none) on dark backgrounds). Elevation is purely background-based.

Scrollbar: rgba(255,255,255,0.1) at rest → rgba(255,255,255,0.2) hover → rgba(255,255,255,0.4) active. 6px width, 10px on hover.

Tone: Engineered restraint. Everything earns its place.


Railway (railway.app) — Visually analyzed via screenshot

See screenshots/railway-homepage.png.

Visual palette observations:

  • Background (hero): Dark desaturated blue-purple, approximately hsl(250, 24%, 9%)#13111C
  • App UI panel (visible in screenshot): Dark surface, same purple-tinted dark family
  • CTA "Deploy" button: Solid purple, approximately #7C3AED (Tailwind purple-600)
  • Navigation background: Near-black with slight purple tint
  • Tab text (active): White. Inactive: muted gray.
  • Announcement banner: Dark purple/indigo gradient

Visual typography observations:

  • Font appears to be Inter (very clean, standard weight interpolation)
  • Navigation uses medium weight (~500)
  • Body copy uses regular weight (400)

Key visual identity:

  • The purple-tinted dark is not the same as WandB's neutral charcoal or Linear's near-black. It has a visible chromatic quality — a cool indigo cast that reads immediately.
  • The "Deploy →" CTA is the most vibrant element on the page — solid purple, high contrast.

Vercel, Inngest, WandB, LangSmith, Grafana — Prior Research

(Based on detailed text analysis from earlier research agents — see competitive-analysis-raw.md)

Vercel: #000000 pure black. Geist + Geist Mono (proprietary). Zero saturation, zero compromise.

Inngest: Stone-950 #0A0A0A warm black. Amber #CBB26A. Whyte + Circular fonts. The warmest palette in the group.

WandB: #1A1C1F charcoal. Cyan #00AFC2 accent. Source Serif 4 headings (unique). Yellow-gold CTAs (#FFCC33→#FFAD33). Explicit 1px solid #34373C card borders.

LangSmith: #030710 near-black with blue cast. Electric blue #4D65FF. JetBrains Mono as primary font — the only site to use monospace as the main UI font.

Grafana: The outlier — white background. Orange #F46800 brand. OSS pragmatism aesthetic.


2. Design Direction

Philosophy

Mission control, not social feed. The ao dashboard should feel like a fighter pilot's HUD — dense, high-contrast, every element load-bearing. Visual analogues: Vercel deployment list discipline + Grafana panel density + LangSmith trace density + Linear state dot pattern.

Dark mode native. Not dark mode as a feature — dark mode as the only mode designed with conviction.

Color = signal, not decoration. Every chromatic element is semantic. Outside status colors, the palette is near-monochrome. This maximizes the signal-to-noise ratio of status indicators.


Color Palette

Inspired by Linear's #08090A and Railway's purple-tinted dark, but finding its own position: a very dark blue-black that reads as technical/precise without being as stark as Vercel's pure black.

Base Palette

Token Hex RGB Usage
--bg-base #0C0C11 12,12,17 Page/app background
--bg-surface #141419 20,20,25 Card backgrounds
--bg-elevated #1C1C25 28,28,37 Hover states, terminal bg, dropdowns
--bg-subtle #23232F 35,35,47 Input backgrounds, code blocks
--border-subtle #22222E 34,34,46 Lowest-visibility borders
--border-default #2E2E3E 46,46,62 Standard card borders
--border-strong #3E3E52 62,62,82 Focus rings, active borders

The blue tint is subtle (~hue 250, saturation ~12%) — enough to read as "technical" rather than "warm", but not as loud as Railway's purple.

Text Hierarchy

Modeled on Linear's verified 4-tier system:

Token Hex Usage
--text-primary #EEEEF5 Main content, titles, session names
--text-secondary #8888A6 Metadata, timestamps, labels
--text-tertiary #50506A Disabled, de-emphasized
--text-inverse #0C0C11 Text on solid-colored buttons

Slight blue tint (EEEEF5 not EEEEEE) harmonizes with the blue-cast background.

Status Colors — Semantic only, never decorative

Token Hex State Notes
--status-working #5B7EF8 Agent actively running Animated pulse
--status-ready #22C55E Needs merge / human to act Highest priority signal
--status-attention #F59E0B Blocked, CI failing, review needed Action required
--status-idle #6B6B8A Agent idle/paused Low visual weight
--status-done #3E3E54 Session complete Visually recedes
--status-error #EF4444 Crash, hard failure Urgent

Note: Linear uses #27A644 for green, #EB5757 for red, #F0BF00 for yellow. ao's status palette is aligned but not identical.

Interactive Accent

Token Hex Usage
--accent #5B7EF8 Links, focus rings, active nav, working state
--accent-hover #7B9CFB Hover state
--accent-subtle rgba(91,126,248,0.12) Highlight backgrounds

Derived from Linear's #4EA7FC blue + their #7070FF brand purple — splitting the difference at a mid-blue-purple that works for both "active" and "interactive" semantic meanings.

Surface Elevation System

Uses background stepping (verified from Linear's approach — no shadows in dark mode):

Page:      #0C0C11  (L ≈ 5%)
Surface:   #141419  (L ≈ 8%)   ← cards, panels
Elevated:  #1C1C25  (L ≈ 12%)  ← hovers, dropdowns, terminals
Subtle:    #23232F  (L ≈ 15%)  ← inputs, inline code

Typography

Font Stack

/* UI — all prose, labels, body */
font-family: "Inter Variable", "SF Pro Display", -apple-system, system-ui, sans-serif;

/* Monospace — branch names, session IDs, terminals, all machine-produced data */
font-family: "Berkeley Mono", "JetBrains Mono", "SF Mono", Menlo, monospace;

Primary recommendation: use Inter Variable — universally available, verified in use by Linear and Supabase (both best-in-class developer dashboards). If budget permits a premium license, Berkeley Mono for monospace matches Linear's actual stack.

Alternative monospace: JetBrains Mono (free, used by LangSmith) — excellent fallback with strong developer tool credibility.

Type Scale

Directly derived from Linear's verified CSS token system:

Name Size (rem) Size (px) Weight Usage
tiny 0.625rem 10px 500 Zone headers (uppercase, +0.10em tracking)
micro 0.75rem 12px 400 Timestamps, secondary metadata (mono)
mini 0.8125rem 13px 400500 Status badges, card metadata rows
small 0.875rem 14px 500 Card titles, primary labels
regular 0.9375rem 15px 400 Body copy within panels
large 1.0625rem 17px 600 Section headings, zone names

Letter spacing: 0.010em to 0.013em for body/mini (matches Linear's verified values). Uppercase zone labels use +0.10em.

Font weights (non-standard for Inter Variable):

  • Regular: 400
  • Medium: 500 (or 510 per Linear's precise variable-font value)
  • Semibold: 590
  • Bold: 680

Component Style

No drop shadows — verified from Linear's CSS: all --shadow-* values resolve to var(--shadow-none) on dark backgrounds. Elevation is exclusively via background color stepping.

1px explicit borders (--border-default: #2E2E3E) on cards — verified from WandB's 1px solid #34373C approach. Border-based cards, not shadow-based.

Border-radius: 6px for cards (Linear's --radius-6). 4px for badges and inputs (--radius-4). 8px for modals/dropdowns (--radius-8).

Transitions: 0.1s for quick (hover states). 0.25s for regular (state changes). Matches Linear's --speed-quickTransition and --speed-regularTransition.


Density

Target: 68 session cards visible without scrolling in the "Working" zone at 1440px.

  • Card height: ~156px compact / ~200px expanded
  • Card width: minmax(260px, 1fr) — 3 columns at 1280px, 4 at 1920px
  • Grid gap: 12px
  • Zone header: 32px
  • Page margin: 20px

This density is closer to Grafana than to Linear. The ao dashboard with 30 agents is a monitoring tool, not a project management tool.


Animation and Motion

One continuous animation only: the working-state activity dot pulse. Everything else is triggered by state change.

@keyframes activity-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(91, 126, 248, 0.4); }
  50%       { box-shadow: 0 0 0 4px rgba(91, 126, 248, 0); }
}

/* Matches Linear's --speed-regularTransition */
transition: background-color 250ms ease, border-color 250ms ease, color 250ms ease;
Element Animation Duration
Working dot Ring pulse (box-shadow) 2s infinite
CI pending Spinner rotation 1.5s linear infinite
Card state change bg + border color 250ms ease
New card appear Fade + 4px slide up 150ms ease-out
Card removal Fade out 200ms ease-in
Terminal expand Height (overflow: hidden) 200ms ease
Merge button hover translateY(1px) 100ms ease

Iconography

Lucide Icons — the shadcn/ui default. 2px stroke weight, clean geometric forms. Pick one library and commit.

Semantic Icon
Working state Custom CSS dot (not SVG)
CI passing CheckCircle2
CI failing XCircle
CI running Loader2 (animated)
Branch GitBranch
PR GitPullRequest
Merge GitMerge
Review comment MessageSquare
Terminal Terminal
Alert/attention AlertTriangle

3. Component Designs

Session Card

The primary unit. Each card = one agent session.

Anatomy:

┌─ 3px status strip ──────────────────────────────────────┐
│                                                          │
│  ● working    session/ao-58                    [···]    │  ← 10px dot + 11px mono ID + menu
│                                                          │
│  Implement UI/UX research dashboard                      │  ← 14px/500 ticket title (2 lines max)
│  GitHub #58                                             │  ← 11px tertiary tracker ref
│                                                          │
│  ⎇ session/ao-58                      ↑ PR #104        │  ← 11px mono branch + PR link
│                                                          │
│  ✓ CI passing    ✓ Approved    3m ago                   │  ← 11px badges + timestamp
│                                                          │
│  [  Terminal  ]                  [ Merge PR → ]         │  ← actions (conditional row)
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual spec:

  • Background: --bg-surface (#141419)
  • Border: 1px solid --border-default (#2E2E3E)
  • Border-radius: 6px (Linear's --radius-6)
  • Padding: 12px 14px
  • Left status strip: 3px wide, full height, color = zone's status color
  • Shadow: none (Linear-verified: no shadows in dark mode)

State variants (tinted border + very subtle tinted background for scanability):

State Strip Border Background tint
Working #5B7EF8 default none
Needs Merge #22C55E rgba(34,197,94,0.2) rgba(34,197,94,0.03)
Needs Attention #F59E0B rgba(245,158,11,0.2) rgba(245,158,11,0.03)
Error #EF4444 rgba(239,68,68,0.2) rgba(239,68,68,0.03)
Done #3E3E54 --border-subtle --bg-base (recedes)

Activity Indicator

8×8px CSS circle (not SVG — simpler, no scaling artifacts).

/* Working — the only continuous animation */
.dot--working {
  background: #5B7EF8;
  animation: activity-pulse 2s ease-in-out infinite;
}

/* States */
.dot--ready     { background: #22C55E; }  /* static — green is enough */
.dot--attention { background: #F59E0B; }  /* static */
.dot--idle      { background: #6B6B8A; }  /* dim, static */
.dot--error     { background: #EF4444; }  /* static */
.dot--done      { background: #3E3E54; }  /* very dim, static */

Label alongside dot: 11px Inter 500, same color as dot.


CI Status Badge

Height 20px, padding 0 8px, border-radius 10px (fully rounded pill).

State Background Text Icon
Passing rgba(34,197,94,0.12) #22C55E CheckCircle2 12px
Failing rgba(239,68,68,0.12) #EF4444 XCircle 12px
Running rgba(91,126,248,0.12) #5B7EF8 Loader2 12px, spinning
Queued rgba(245,158,11,0.12) #F59E0B Clock 12px
Skipped rgba(107,107,138,0.12) #6B6B8A Minus 12px

Text: always present (never icon-only). 11px Inter 500. "Passing" / "Failing" / "Running".

Multiple jobs: show worst-state badge. Hover expands to popover with all job names.


PR Merge Button

The highest-priority action. When ready, must visually dominate the card.

Ready:

background: #22C55E;
color: #0C0C11;        /* dark text on green */
height: 28px;
padding: 0 12px;
border-radius: 6px;    /* Linear's --radius-6 */
font: 12px/1 "Inter Variable" 600;
/* icon: GitMerge 14px left of "Merge PR" label */
transition: transform 100ms ease, filter 100ms ease;
&:hover { transform: translateY(-1px); filter: brightness(1.05); }

Blocked — CI/review:

background: #1C1C25;
color: #50506A;
border: 1px solid #2E2E3E;
cursor: not-allowed;
/* tooltip explains why */

Conflicts:

background: rgba(239,68,68,0.12);
color: #EF4444;
border: 1px solid rgba(239,68,68,0.3);
label: "Conflicts";

After merge (optimistic):

background: rgba(34,197,94,0.12);
color: #22C55E;
label: "Merged ✓";

One click, no confirmation modal. Merging a reviewed PR is the goal state — friction is the enemy.


Terminal Panel

Location: Right-side drawer (preferred — doesn't reflow the 30-card grid).

Width:    480px or 40vw (whichever larger)
Slide in: transform translateX(100%) → translateX(0), 200ms ease
Backdrop: rgba(0,0,0,0.4)

Terminal area:

background: #0A0A0F;           /* deeper than card surface */
font: 13px/1.5 "Berkeley Mono", "JetBrains Mono", Menlo, monospace;
color: #D4D4D8;                /* standard terminal foreground */
/* cursor: block, #5B7EF8 — brand blue distinguishes from content */
padding: 12px 16px;
scrollbar-width: 4px;
scrollbar-color: rgba(255,255,255,0.1) transparent;

Log format: timestamp in --text-tertiary · content in --text-primary. Orchestrator-injected messages shown in rgba(91,126,248,0.2) highlight.


Attention Zone Headers

5 zones ordered by priority (top to bottom):

  1. Needs Merge — PRs approved + CI passing
  2. Needs Response — review comments, CI failures, conflicts
  3. Working — agents running fine
  4. Idle — agents paused/inactive
  5. Done — completed, ready for cleanup

Header anatomy:

[●] NEEDS MERGE  ─────────────────────────────  [3]
 ↑               ↑                               ↑
 8px dot    flex-1 1px border-subtle         count pill
.zone-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0;
  margin: 20px 0 12px;
}
.zone-label {
  font: 10px/1 "Inter Variable" 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  /* color: zone's status color */
}
.zone-divider {
  flex: 1;
  height: 1px;
  background: var(--border-subtle);
}
.zone-count {
  font: 11px/1 "Inter Variable" 500;
  padding: 2px 7px;
  border-radius: 10px;
  /* background + color: zone's status color at 12% opacity */
}
Zone Color Empty behavior
Needs Merge #22C55E Collapse entirely
Needs Response #F59E0B Collapse entirely
Working #5B7EF8 Collapse if zero
Idle #6B6B8A Collapse by default
Done #3E3E54 Collapsed by default

4. Inspiration References

Linear issue list — the density benchmark

URL: https://linear.app (see screenshots/linear-homepage.png)
Why: The product UI visible in Linear's homepage hero screenshot shows exactly the information density and row compactness that ao session cards should match. Issue ID in muted monospace, title truncated, labels as small pill badges, state dot left-aligned. Zero wasted pixels.

Vercel deployment list

URL: https://vercel.com/dashboard
Why: Each deployment row = name (mono) + status dot + branch + timestamp. The status dot on a near-black background carries the full state signal with nothing competing. This is the right level of restraint for ao's done/idle sessions.

GitHub Actions job graph

URL: https://docs.github.com/en/actions/writing-workflows/quickstart
Why: Status-colored nodes (green pass, red fail, gray skip, amber running) in a dependency graph. The best existing model for "pipeline state at a glance." The icon+color combination for each step is directly applicable to ao's CI status display.

Grafana panel layout — density reference

URL: https://grafana.com/grafana/dashboards
Why: Demonstrates that 30+ data panels in one viewport is possible — when organized by visual weight, semantic color, and zone separation. The panel border system (1px subtle border, consistent padding, consistent label typography) is the right density model for ao's session card grid.

GitHub Copilot agent mode in VS Code

URL: https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode
Why: Sequential labeled tool invocations ("Analyzing files... Running tests... Proposing edits...") is the right model for ao's terminal activity feed — transparent step disclosure rather than raw log dump. Each step collapsible. Makes AI activity legible rather than just visible.


5. What to Avoid

Anti-patterns for this product specifically

1. Spacious card proportions — ao has 30 sessions. Linear/Notion card sizes assume 1 project per screen.

2. Status color overloading — Define strict semantic rules. Amber = "needs human attention." Green = "positive outcome / merge-ready." Red = "error/failure." Never use the same color for two different meanings.

3. Badge spam — Show only badges that diverge from the happy path. CI passing = expected = no badge. CI failing = show badge. If everything is highlighted, nothing is.

4. Modal confirmation for merge — Pre-approved PRs are the goal state. One click. Destructive actions (kill session, delete worktree) use confirmation. Merge does not.

5. Wide sidebar — A 240px sidebar wastes 240px of card grid space. Use a 48px icon rail or a 32px top bar.

6. Light mode as design authority — Design dark first. If you design light first you get light-mode thinking applied to dark backgrounds.

7. Competing animations — One continuous animation (working dot pulse). Everything else is state-change triggered.

8. Full-width single-column — 30 sessions in a single column is 5 viewports tall. Grid layout is mandatory.

9. Burying the terminal — Terminal is a primary debugging surface. One click from any session card.

10. Generic icon library mixing — Pick Lucide or Heroicons. Use it everywhere. One icon per semantic concept.

11. Done sessions at full visual weight — Done cards must visually recede (dim colors, collapsed by default). The eye should skip them automatically.

12. Conflating activity state and attention state — These are separate dimensions. A working agent can need response (CI failing). An idle agent can be merge-ready. Show both independently: left strip = attention state, dot = activity state.


6. Implementation Stack Recommendation

Frontend: Next.js 15 (App Router) + Tailwind CSS 4 + shadcn/ui (Radix UI primitives)

  • Matches ao's existing stack
  • Used by Supabase at scale — validated for serious developer tooling

Design tokens: CSS custom properties on :root. All colors defined as tokens, not Tailwind classes directly. Enables runtime theming and makes the semantic system enforceable.

Terminal: xterm.js + @xterm/addon-fit. Dark theme with the color system above.

Real-time: Server-Sent Events (existing in ao's architecture). State transitions animate via CSS transition (250ms ease).

Icons: lucide-react (npm package, tree-shakeable). Same package used by shadcn/ui components.

Accessibility: Status indicators never rely on color alone — always paired with text label or icon. Focus rings use --accent at 2px offset. Tab order follows visual reading order.


7. Current Implementation Audit

Added after reading the actual packages/web/ codebase. Maps recommendations to real files.

Existing Component Inventory

File Purpose Status
packages/web/src/app/globals.css CSS design tokens (@theme block) Token system in place, needs repalette
packages/web/src/components/Dashboard.tsx Top-level layout: header, stats bar, attention zones, PR table Well structured
packages/web/src/components/AttentionZone.tsx Zone header + collapsible session list Functional, visual polish needed
packages/web/src/components/SessionCard.tsx Primary card unit with left border strip, alerts, expand panel Core logic solid, visual refinement needed
packages/web/src/components/CIBadge.tsx CI check status display Exists
packages/web/src/components/PRStatus.tsx PR state display + table row Exists
packages/web/src/components/DirectTerminal.tsx xterm.js + WebSocket terminal (full-page /sessions/:id) Fully implemented
packages/web/src/lib/types.ts DashboardSession, AttentionLevel, getAttentionLevel() Well typed

packages/web/src/app/globals.css uses a GitHub-inspired palette. The recommended brief palette is a blue-cast dark. Mapping:

Token Current (GitHub) Recommended (Brief) Delta
--bg-base / --color-bg-primary #0d1117 (13,17,23) #0C0C11 (12,12,17) Very close. GitHub has more blue+green, brief more neutral-blue.
Surface / --color-bg-secondary #161b22 (22,27,34) #141419 (20,20,25) GitHub bluer, brief more neutral. Similar luminance.
Elevated / --color-bg-tertiary #1c2128 (28,33,40) #1C1C25 (28,28,37) GitHub bluer.
--color-border-default #30363d #2E2E3E GitHub has green tint, brief is blue-neutral.
--color-text-primary #e6edf3 #EEEEF5 GitHub slightly cooler-white; brief slightly warmer.
--color-text-secondary #7d8590 #8888A6 GitHub gray; brief has slight blue cast.
Accent blue #58a6ff #5B7EF8 Brief's blue is shifted toward indigo.
Green #3fb950 #22C55E Brief's green is more vibrant/saturated.
Red #f85149 #EF4444 Very similar.
Yellow #d29922 #F59E0B Brief is brighter/more saturated.

Assessment: The current palette is functional and coherent. The recommended palette shifts from GitHub's blue-green cast to a more neutral blue-indigo cast. Both work; the brief's palette aligns more closely with Linear/LangSmith's positioning than GitHub's.

globals.css body font:

font-family: -apple-system, BlinkMacSystemFont, "SF Pro", system-ui, sans-serif;

--font-mono:

--font-mono: "SF Mono", "Menlo", "Consolas", monospace;

Brief recommendation: "Inter Variable" as primary, "Berkeley Mono" / "JetBrains Mono" as monospace.

Practical path:

  • Swap body to "Inter Variable", ... — load via next/font/google (no license cost). This is the highest-impact single change.
  • Swap monospace to "JetBrains Mono", "SF Mono", Menlo, monospace — JetBrains Mono is free, available via Google Fonts, and widely recognized in developer tooling (LangSmith uses it).
  • Berkeley Mono requires a paid license — use as optional upgrade if budget permits.

Current AttentionZone.tsx header structure:

[ZONE LABEL]  [description text]                    [count pill] [▼]

Brief recommendation:

[●] ZONE LABEL  ─────────────────────────────────────── [count pill]

The current implementation adds a description text (e.g., "PRs ready to merge"). This is informative for new users but creates visual clutter at density. The brief's divider-line approach is more compact and scales better with 30+ sessions.

Collapse behavior: Current correctly collapses "done" by default and returns null when empty — matches brief recommendation.

6-level zone system matches brief: merge → respond → review → pending → working → done.

What the current card gets right:

  • 3px left border strip colored by attention level
  • Left strip color mapped to borderColorByLevel record
  • Merge-ready: green border highlight + prominent "merge PR #N" button
  • Alert badges for CI failures, review requests, conflicts, unresolved comments
  • Expandable detail panel with CI checks, unresolved comments, PR diff stats
  • Activity icons for each ActivityState

What diverges from brief:

  1. Activity icons are Unicode emoji (, 🟢, 💤, , 🚧, 💀) — brief recommends 8×8px CSS circles with color semantics. Emoji are charmingly informal but inconsistently sized across platforms and don't carry precise color semantics. The CSS dot approach is more precise.

  2. Merge button is translucent (rgba(63,185,80,0.2) bg with #3fb950 text) — brief recommends solid green (#22C55E background, dark text). Solid green for the primary action makes it visually dominate correctly.

  3. Card border-radius is 10px (set inline with style={{ borderRadius: 10 }}) — brief recommends 6px (Linear's --radius-6). Minor but affects overall tightness.

  4. confirm() dialog on merge — brief explicitly recommends one-click merge without modal. The current if (!confirm(...)) on line 66 of Dashboard.tsx adds friction for the primary happy-path action. Kill/terminate should keep the confirm; merge should not.

  5. Single-column list layout — cards stack vertically within each zone. Brief recommends a multi-column grid for density. At 30 sessions, single-column requires significant scrolling. Grid at minmax(300px, 1fr) with gap: 12px would show 3 columns at 1100px viewport, matching brief density target.

Real-time Updates: Gap

packages/web/src/lib/types.ts defines SSESnapshotEvent and SSEActivityEvent — the SSE contract is designed. However, the dashboard currently fetches data at page load only (server-side, via page.tsx). No client-side SSE listener exists.

Brief recommendation: SSE subscription on /api/events to receive session.activity updates and re-render affected cards without full refresh.

Files to add this to:

  • packages/web/src/components/Dashboard.tsx — add useEffect with EventSource to subscribe to /api/events
  • On session.activity event: update the session in local state and allow CSS transition to reflect new attention level

Design Deltas Summary (Priority Order)

Priority Change File Impact
1 Load Inter Variable via next/font/google packages/web/src/app/layout.tsx Typography lift — biggest visual delta
2 Load JetBrains Mono via next/font/google packages/web/src/app/layout.tsx Monospace consistency
3 Swap globals.css color tokens to brief palette packages/web/src/app/globals.css Color system coherence
4 Merge button: solid green background, no confirm packages/web/src/components/SessionCard.tsx, Dashboard.tsx Primary action clarity
5 Replace emoji activity icons with CSS dots packages/web/src/components/SessionCard.tsx Visual precision, cross-platform consistency
6 Zone header: divider-line layout instead of description text packages/web/src/components/AttentionZone.tsx Density
7 Multi-column grid for session cards packages/web/src/components/AttentionZone.tsx Density at scale
8 Card border-radius: 10px → 6px packages/web/src/components/SessionCard.tsx Tighter, more Linear-aligned
9 SSE live-reload subscription packages/web/src/components/Dashboard.tsx Real-time updates
10 Right-side drawer for terminal (vs. full-page nav) New component or DirectTerminal.tsx Workflow: stay in dashboard while monitoring

Appendix: Raw Research Notes

See competitive-analysis-raw.md for full text-based analysis of all 14 competitor sites.
See screenshots/ for Playwright-captured screenshots of Linear and Railway.

Companion Documents

All three pages share this token system and theme:

Document Page Focus
design-brief.md (this file) / — Main dashboard Session grid, attention zones, triage
session-detail-design-brief.md /sessions/[id] Terminal + PR investigation
orchestrator-terminal-design-brief.md /sessions/[orchestrator-id] Command center, full-viewport terminal

Design brief v2. Compiled February 2026.
Research methods: Playwright CSS extraction (Linear), Playwright screenshots (Linear, Railway), text-based web analysis (all others).
Codebase audit: Read packages/web/src — globals.css, Dashboard.tsx, SessionCard.tsx, AttentionZone.tsx, types.ts, DirectTerminal.tsx.
Precision note: Linear color/typography values are verified from live CSS. Railway values are visually estimated from screenshot. All others are from text/HTML analysis.