# 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`. 3–5 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 | 0–599px | Mobile | Bottom Nav | 1 |
| Medium | 600–1023px | 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)

```scss
// _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

```typescript
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;         // 0–100
  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

```typescript
// 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

```css
/* 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)*
