Files
Control-Center/design/command-hub-spec.md
cubecraft-agents[bot] f490098af6 initial commit
2026-04-25 19:02:57 +00:00

20 KiB
Raw Permalink Blame History

OpenClaw Control Center — Command Hub

Senior Product Designer Specification (7-Point)

Version: 1.0
Date: 2026-04-21
Designer: Sketch (UI/UX Agent)
Status: Implementation-Ready
Design System: Material Design 3 (https://m3.material.io/)
Aesthetic: Tactical Dark Mode


1. Objective

Design the Command Hub — the primary entry point and nerve centre for the OpenClaw Control Center. This screen enables operators to monitor all active agents at a glance, assess fleet health in under 3 seconds, and jump directly into any agent session without friction.

The design must serve two primary mental models:

  • Triage Mode — scan for errors, stalls, and anomalies fast
  • Navigation Mode — get into a specific agent session instantly

This is a utility-first, operator-grade interface. It is not a marketing page. Every pixel earns its place.


2. Screen Inventory

Screen Description Trigger
Command Hub Fleet Status grid + global nav App launch / Home
Agent Session View Full session detail for one agent Quick-Jump tap
Session Log Full scrollable log history Long-press agent card or log icon
Task Breakdown Subtask waterfall for active task Tap active task chip on card
Settings / Config Global config, theme, agents list Nav Rail → Settings
Notifications Panel Alert history and system events Bell icon / swipe

3. Layout Specification

3.1 Kiosk Layout (≥ 1024px — Fixed Display / Raspberry Pi HDMI)

┌─────────────────────────────────────────────────────────────────┐
│  NAV RAIL (72px)  │           MAIN CONTENT AREA                  │
│                   │                                               │
│  [☰] OpenClaw     │  ┌─ HEADER BAR ─────────────────────────┐   │
│                   │  │  "Command Hub"    [🔔 3] [●Live] [⚙]  │   │
│  [⚡] Command Hub │  └──────────────────────────────────────┘   │
│  [📋] Projects    │                                               │
│  [🗂] Sessions    │  ┌─ FLEET STATUS ────────────────────────┐   │
│  [📊] Logs        │  │  FILTER: [All ▾]  [Active] [Error]    │   │
│  ─────────        │  │                                        │   │
│  [⚙] Settings    │  │  ┌──────────┐ ┌──────────┐ ┌──────┐   │   │
│  [👤] Profile     │  │  │ AGENT    │ │ AGENT    │ │AGENT │   │   │
│                   │  │  │  CARD    │ │  CARD    │ │ CARD │   │   │
│                   │  │  └──────────┘ └──────────┘ └──────┘   │   │
│                   │  │  ┌──────────┐ ┌──────────┐ ...        │   │
│                   │  │  │ AGENT    │ │ AGENT    │            │   │
│                   │  │  │  CARD    │ │  CARD    │            │   │
│                   │  │  └──────────┘ └──────────┘            │   │
│                   │  └────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Nav Rail: 72px collapsed, 256px expanded. M3 NavigationRail component. Always visible on kiosk.

Main Content: 3-column agent card grid (CSS Grid, repeat(auto-fill, minmax(340px, 1fr))). 24px gutter.

Header Bar: 64px tall. App title + live indicator + notification bell + settings.


3.2 Mobile Layout (< 768px — Phone / Tablet)

┌───────────────────────────────┐
│  ┌─ HEADER ──────────────────┐│
│  │ ≡  Command Hub   🔔 ⚙    ││
│  └────────────────────────────│
│                                │
│  [All ▾] [Active 4] [Error 1] │
│                                │
│  ┌──────────────────────────┐ │
│  │  AGENT CARD (full width) │ │
│  └──────────────────────────┘ │
│  ┌──────────────────────────┐ │
│  │  AGENT CARD (full width) │ │
│  └──────────────────────────┘ │
│  ┌──────────────────────────┐ │
│  │  AGENT CARD (full width) │ │
│  └──────────────────────────┘ │
│                                │
│ ─────────────────────────────  │
│  [⚡Hub] [📋Projects] [📊Logs] │
│       BOTTOM NAV BAR           │
└───────────────────────────────┘

Bottom Navigation: M3 NavigationBar. 35 destinations. Active destination uses M3 indicator pill.

Cards: Single-column, full-width. Scrollable list. 16px horizontal padding.


3.3 Agent Card Component (Core Unit)

┌─────────────────────────────────────────────────────┐
│  ● ACTIVE          [otto]              [→ Jump]      │
│  ─────────────────────────────────────────────────── │
│  🤖  Otto                                            │
│      Orchestrator Agent                              │
│                                                      │
│  TASK:  Reviewing PR #42 — extrudex-ui               │
│  ████████████░░░░░░  62% — 04m 12s elapsed           │
│                                                      │
│  SESSION: agent:otto:telegram:direct:8787...         │
│  CHANNEL: Telegram  [●] Last msg: 2m ago             │
└─────────────────────────────────────────────────────┘

Card anatomy:

  • Status Badge (top-left): Color pill — Active / Idle / Thinking / Error
  • Agent Tag (top-center): Short ID chip
  • Quick-Jump CTA (top-right): → Jump icon button — M3 FilledTonalIconButton
  • Avatar + Name + Role (mid-section): M3 List tile pattern
  • Active Task Row: Task name + linear progress indicator
  • Session Footer: Session key truncated + channel + last activity timestamp

Card states:

  • Default — surface container background, subtle border
  • Active — cyan left-border accent (4px), slightly elevated +2dp
  • Error — red border, pulsing status dot
  • Thinking — purple status + animated shimmer on task row
  • Idle — muted, desaturated, lower elevation
  • Hover/Focus — M3 state layer overlay (8% primary)

3.4 Quick-Jump Mechanism

On tap of → Jump button on any agent card:

  1. Modal Bottom Sheet (mobile) — M3 ModalBottomSheet slides up with:

    • Agent name + status
    • Last 3 messages (truncated)
    • [Open Full Session] FAB
    • [View Logs] secondary action
  2. Side Drawer Panel (kiosk/desktop) — M3 NavigationDrawer (modal variant) slides in from right (480px wide) with:

    • Agent name + session context
    • Live log tail (last 20 lines, auto-scroll)
    • [Open Full Session] primary button
    • [Pin to Dashboard] secondary action

Keyboard / touch shortcut: Long-press card = opens Session Log directly (bypasses Quick-Jump drawer).


3.5 Global Navigation Structure

Destination Icon Badge
Command Hub Flash None
Projects 📋 Clipboard Active count
Sessions 🗂 Stack Unread count
Logs 📊 Chart Error count
Settings ⚙ Gear

Rail behavior: Collapsed by default on kiosk. Tap hamburger to expand with labels.
Bottom nav (mobile): Always shows labels. Max 5 destinations. Overflow → menu.


4. UX Rationale

Why Navigation Rail (Desktop) + Bottom Nav (Mobile)?

M3's adaptive navigation pattern — NavigationRail is the correct M3 component for persistent navigation on expanded screens. It keeps the full content width for the fleet grid. On mobile, NavigationBar (bottom) is ergonomically correct for thumb reach. The two layouts share identical navigation destinations but adapt the component.

Why Card Grid, Not Table?

  • Cards are touch-friendly (minimum 56px tap area per cell)
  • Cards support rich visual status — tables flatten the hierarchy
  • Cards allow progressive disclosure (collapsed vs expanded state)
  • Tables are for data comparison; cards are for status triage

Why Quick-Jump Drawer, Not Page Navigation?

Operators often want to peek at an agent without losing the fleet overview. A drawer preserves context — the fleet grid remains visible behind it. Full navigation to the agent session view is a secondary action requiring intentional tap.

Why Left-Border Accent on Active Cards?

It's a scannable, pre-attentive visual cue. Eyes detect vertical color stripes faster than color fills. Lifted from terminal/IDE design patterns (like VS Code activity indicators). Consistent with Tactical Dark Mode aesthetics.

Information Hierarchy on Card

Status → Identity → Current Task → Session Context
This ordering maps to the triage mental model: "Is it ok? Who is it? What's it doing? Where is it?"


5. Visual Direction

5.1 Color Palette (M3 Dynamic Color — Custom Dark Scheme)

Role Token Hex Usage
Background md.sys.color.background #0D0F12 App background
Surface md.sys.color.surface #13161A Card background
Surface Container md.sys.color.surface-container #1C2027 Elevated cards
Surface Container High md.sys.color.surface-container-high #252B33 Header, Nav Rail
On Surface md.sys.color.on-surface #E2E8F0 Primary text
On Surface Variant md.sys.color.on-surface-variant #8A9BB0 Secondary text
Outline md.sys.color.outline #2D3748 Card borders
Primary md.sys.color.primary #38BDF8 Active state, CTAs (Electric Blue)
On Primary md.sys.color.on-primary #0C1825 Text on primary
Secondary md.sys.color.secondary #64748B Nav inactive
Tertiary md.sys.color.tertiary #A78BFA Thinking state (Amethyst)

Status Colors (Semantic — outside M3 tonal system):

Status Color Hex Dot Animation
Active Electric Blue #38BDF8 Steady pulse (2s)
Idle Muted Teal #2DD4BF Static
Thinking Amethyst #A78BFA Slow pulse (3s)
Error Vivid Red #F87171 Fast pulse (0.8s)

5.2 Typography

M3 Type Scale using Inter (primary) with Roboto Mono for session IDs and log output.

Role M3 Token Size Weight Usage
Display Small displaySmall 36sp 400 Screen title
Headline Medium headlineMedium 28sp 400 Agent name
Title Large titleLarge 22sp 500 Section headers
Title Medium titleMedium 16sp 500 Card title
Body Medium bodyMedium 14sp 400 Task description
Label Large labelLarge 14sp 500 Buttons, badges
Label Small labelSmall 11sp 500 Status chips, timestamps
Mono Body 13sp 400 Session IDs, log text

5.3 Elevation & Surfaces

Using M3's tonal surface elevation (not drop shadows):

Level Overlay Usage
Level 0 0% App background
Level 1 5% Cards (default)
Level 2 8% Cards (active/hover)
Level 3 11% Navigation Rail
Level 4 12% Header / App Bar
Level 5 14% Modal overlays

5.4 Spacing & Grid

  • Base unit: 8px
  • Card padding: 20px (2.5 units)
  • Card gap (grid): 16px (2 units)
  • Section padding: 24px (3 units)
  • Nav Rail width collapsed: 72px
  • Nav Rail width expanded: 256px
  • Card min-width: 320px, preferred: 360px
  • Card border-radius: 16px (M3 ExtraLarge shape token)
  • Status dot size: 10px

5.5 Iconography

M3 Material Symbols (Outlined weight, FILL=0, wght=400, GRAD=0, opsz=24).

Key icons:

  • Agent status dot: Custom SVG animated circle
  • Quick-Jump: arrow_forward or open_in_new
  • Active: bolt
  • Thinking: psychology or autorenew
  • Error: error_outline
  • Idle: pause_circle
  • Settings: settings
  • Notifications: notifications

6. Responsiveness

Breakpoints (M3 Adaptive Layout)

Breakpoint Width Layout Navigation Columns
Compact 0599px Mobile Bottom Nav 1
Medium 6001023px Tablet Nav Rail (collapsed) 2
Expanded ≥ 1024px Desktop/Kiosk Nav Rail (expandable) 3+

Adaptive Behaviors

Compact (Phone):

  • Cards: Full-width, stacked vertically
  • Quick-Jump: Modal Bottom Sheet
  • Header: Small top app bar (M3 SmallTopAppBar)
  • Status filter: Horizontal scroll chip group

Medium (Tablet):

  • Cards: 2-column grid
  • Nav Rail: Collapsed (icons only)
  • Quick-Jump: Side panel (half-width drawer)

Expanded (Kiosk/Desktop):

  • Cards: 3+ column auto-fill grid
  • Nav Rail: Expandable with labels
  • Quick-Jump: Side drawer (480px)
  • Header: Medium top app bar with subtitle

Touch Targets

  • All interactive elements: minimum 48×48dp (M3 spec)
  • Card tap area: full card (not just button)
  • Quick-Jump button: 56×56dp (touch-optimized)
  • Bottom nav items: minimum 48dp height

7. Developer Handoff Notes

7.1 Technology Stack

  • Frontend: Angular 17+ with Angular Material (M3 theming)
  • Realtime: SignalR WebSocket hub — AgentStatusHub
  • State Management: NgRx (recommended) or Angular Signals
  • Styling: Angular Material theming + custom CSS custom properties for status colors

7.2 M3 Theme Configuration (Angular Material)

// _theme.scss
@use '@angular/material' as mat;

$dark-theme: mat.define-theme((
  color: (
    theme-type: dark,
    primary: mat.$cyan-palette,      // #38BDF8 family
    tertiary: mat.$violet-palette,   // #A78BFA family
  ),
  typography: (
    brand-family: 'Inter, sans-serif',
    plain-family: 'Inter, sans-serif',
    bold-weight: 600,
    medium-weight: 500,
    regular-weight: 400,
  ),
  density: (
    scale: 0,
  ),
));

// Custom CSS vars for status colors
:root {
  --status-active: #38BDF8;
  --status-idle: #2DD4BF;
  --status-thinking: #A78BFA;
  --status-error: #F87171;
  --status-active-bg: rgba(56, 189, 248, 0.12);
  --status-error-bg: rgba(248, 113, 113, 0.12);
}

7.3 Agent Card Component Interface

interface AgentCardData {
  id: string;                    // e.g., "otto"
  displayName: string;           // e.g., "Otto"
  role: string;                  // e.g., "Orchestrator Agent"
  status: AgentStatus;           // 'active' | 'idle' | 'thinking' | 'error'
  currentTask?: string;          // e.g., "Reviewing PR #42"
  taskProgress?: number;         // 0100
  taskElapsed?: string;          // e.g., "04m 12s"
  sessionKey: string;            // full session key
  channel: string;               // e.g., "telegram"
  lastActivity: Date;
  errorMessage?: string;         // populated on error state
}

type AgentStatus = 'active' | 'idle' | 'thinking' | 'error';

7.4 SignalR Integration

// agent-status.service.ts
export class AgentStatusService {
  private hubConnection: HubConnection;

  connect() {
    this.hubConnection = new HubConnectionBuilder()
      .withUrl('/hubs/agent-status')
      .withAutomaticReconnect()
      .build();

    this.hubConnection.on('AgentStatusChanged', (update: AgentStatusUpdate) => {
      this.store.dispatch(AgentActions.statusUpdated({ update }));
    });

    this.hubConnection.on('AgentTaskProgress', (progress: TaskProgressUpdate) => {
      this.store.dispatch(AgentActions.taskProgressUpdated({ progress }));
    });
  }
}

7.5 Animation Specs

/* Status dot pulse animations */
@keyframes pulse-active {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.7; transform: scale(1.15); }
}

@keyframes pulse-error {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

@keyframes pulse-thinking {
  0%, 100% { opacity: 0.8; }
  50% { opacity: 0.4; }
}

.status-dot--active  { animation: pulse-active  2s ease-in-out infinite; }
.status-dot--error   { animation: pulse-error   0.8s ease-in-out infinite; }
.status-dot--thinking { animation: pulse-thinking 3s ease-in-out infinite; }
.status-dot--idle    { /* static */ }

/* Quick-jump card border accent */
.agent-card--active  { border-left: 4px solid var(--status-active); }
.agent-card--error   { border-left: 4px solid var(--status-error); }
.agent-card--thinking { border-left: 4px solid var(--status-thinking); }
.agent-card--idle    { border-left: 2px solid var(--md-sys-color-outline); }

7.6 Angular Component Structure

src/app/
  command-hub/
    command-hub.component.ts       ← Shell, grid layout
    command-hub.component.html
    command-hub.component.scss
    components/
      agent-card/
        agent-card.component.ts    ← Core card unit
        agent-card.component.html
        agent-card.component.scss
      fleet-status-filter/
        fleet-status-filter.component.ts
      quick-jump-drawer/
        quick-jump-drawer.component.ts  ← Side drawer (desktop)
      quick-jump-sheet/
        quick-jump-sheet.component.ts   ← Bottom sheet (mobile)
    services/
      agent-status.service.ts
    store/
      agent.actions.ts
      agent.reducer.ts
      agent.selectors.ts
      agent.effects.ts

7.7 Accessibility

  • All status indicators must have text alternatives (aria-label="Status: Active")
  • Cards are role="article" with aria-labelledby pointing to agent name
  • Color is never the ONLY differentiator — icons accompany all status colors
  • Focus ring: M3 focus indicator (3dp ring, md.sys.color.secondary)
  • Reduced motion: all pulse animations respect prefers-reduced-motion: reduce
  • Live region for status changes: aria-live="polite" on status badge

7.8 Performance Notes

  • Agent cards use @defer (Angular 17) for lazy rendering below the fold
  • SignalR updates trigger only targeted card updates via NgRx selectors (no full re-render)
  • Status dot animations use will-change: transform, opacity for GPU compositing
  • Limit fleet grid to visible viewport; virtual scroll for > 20 agents (@angular/cdk/scrolling)

Appendix A: Status Color Reference Card

● #38BDF8  ACTIVE    — Agent currently processing a task
● #2DD4BF  IDLE      — Agent online, no active task
● #A78BFA  THINKING  — Agent processing/reasoning (LLM call in flight)
● #F87171  ERROR     — Agent encountered an unhandled error
○ #64748B  OFFLINE   — Agent unreachable / session terminated

Appendix B: Quick-Jump UX Flow

User taps [→ Jump] on Agent Card
         │
         ├─ Desktop/Kiosk ──► Right side drawer slides in (480px)
         │                     Shows: live log tail, last msgs, [Open Full Session]
         │
         └─ Mobile ──────────► Modal Bottom Sheet rises
                                Shows: agent name, 3 recent msgs, [Open Full Session]
                                
User taps [Open Full Session]
         │
         └─ Router navigate to /sessions/:agentId
            Full page Agent Session View

Spec v1.0 — Ready for implementation. Questions → Sketch (UI/UX Agent)