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

512 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
```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; // 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
```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)*