Agent Surfaces — Design & Implementation Spec

Status: Design locked 2026-04-20 · awaiting implementation plan · companion to Mission-Control-Product-Spec.md

Scope: Four presence tiers for interacting with the 5 Mission Control agents — dashboard landing, subtle persistent companion, single-agent war room, multi-agent war room.

Decision rationale: See the four HTML previews referenced under Companion Documents; design picks locked via the Rule 34 HTML-preview protocol.

◉ Table of Contents
  1. Overview
  2. Problem Statement
  3. Scope
  4. User Journeys
  5. Architecture — Four Surfaces
  6. Shared Components
  7. IPC & API Contracts
  8. State Machines
  9. Persistence Rules
  10. Data Feeds Required
  11. Trust & Privacy
  12. Performance Budgets
  13. Mobile/PWA Degradation
  14. Accessibility
  15. Test Strategy
  16. Implementation Phases
  17. Open Questions
  18. Companion Documents

1 · Overview

The current /voice page is a generic voice-chatbot surface — violet "S" circle, waveform strip, "Start Voice Session" button. It's functional but impersonal and does not match the "mission control / command center" feel the product requires. Additionally, there is no tiered presence model — Shakeeb is either absent (every non-voice screen) or all-consuming (the voice page). This spec replaces that binary with a four-tier presence stack:

#SurfaceWhen you use itDominant agent(s)
1Dashboard landingEntry, agent picking, at-a-glance status5 (all agents visible)
2Subtle presenceWorking in Email / Calendar / Memory / any non-war-room screen1 (current agent)
3War room · singleFocused conversation / extended session with one agent1 (immersive JARVIS-feel)
4War room · multiRunning more than one agent in parallel2–5 (adaptive grid + focus-swap)

The four surfaces share the same agent state, transcript, and trust contract. A user swaps between them without losing conversational continuity. There is no "session" that starts and ends — presence tier is a lens on the same persistent context (matches JARVIS-feel signature #7 "no session boundaries").

2 · Problem Statement

  1. The current /voice UI does not communicate that Shakeeb is a character — it reads as a generic chatbot.
  2. Shakeeb has no presence outside /voice — when working in other screens, he effectively doesn't exist unless explicitly summoned. This is the opposite of an always-on assistant.
  3. There is no planned topology for multi-agent interaction. Phase 2 (BRX) and Phase 3 (Jean Otti, Nadzingo, Kamini) will need a shared surface, and bolting it on late is more expensive than architecting for it now.
  4. The "draft-first trust contract" requires visible surfaces (draft queue, approval prompts, proactive suggestions). None of these exist in today's /voice.

3 · Scope

In scope (this spec)

Out of scope

4 · User Journeys

J1 — Morning walk-in. User opens the desktop app. Dashboard landing shows all 5 agents as portraits. Shakeeb strip up top shows "Morning Wassim — three items: Sarah's Dubai reply, Sam at three, Mariam's pricing follow-up." User clicks Shakeeb card → enters war room (single) with context already loaded. No login, no "start session."

J2 — Working in Email. User navigates to /email. Right rail docks with Shakeeb listening + last 3 turns of transcript. User types "draft a reply to Sarah, apologetic tone" into rail input. Shakeeb drafts in the queue module. User hits to collapse rail to corner orb; orb pulses when draft is ready for review. User clicks orb → rail expands back.

J3 — Extended focus session. User hits ⌘J (or clicks "War Room →" in rail) from anywhere. Enters war room (single-agent, v3 JARVIS). All HUD modules materialize. Session persists; closing the app and reopening tomorrow picks up with "continuity banner: picking up from yesterday 18:42."

J4 — Multi-agent parallel work (Phase 2+). User starts BRX on a car research task, Jean Otti on a Reddit scan, Kamini on an arsenal audit. Enters multi-agent war room at /war-room. All three visible as 1×3 adaptive grid. When BRX has results, his orb pulses in the grid. User clicks BRX name in the top bar → grid animates into focus+satellites with BRX in center, Jean Otti + Kamini as satellites at the corners. User then clicks Jean Otti's satellite → BRX swaps to satellite, Jean Otti blooms to center.

J5 — Mobile/PWA quick check. User opens PWA on phone. Dashboard landing degrades to single-column agent cards. Tapping Shakeeb opens a mobile-adapted subtle presence (bottom sheet variant, not corner orb). No war room on mobile — too dense. Prompt: "open on desktop for the full war room."

5 · Architecture — Four Surfaces

Surface 1 — Dashboard landing

Surface 2 — Subtle presence (rail ↔ corner orb)

Surface 3 — War room · single (JARVIS-feel, v3 density)

Surface 4 — War room · multi (adaptive + focus-swap)

6 · Shared Components

ComponentUsed byPath (target)
<AgentOrb codename="atlas" size={…} state={…}/>All 4 surfacessrc/renderer/components/agents/AgentOrb.tsx
<AgentRings variant="single"|"quadrant"|"hero"/>Surfaces 3, 4src/renderer/components/agents/AgentRings.tsx
<PresenceRail/> (collapsible)Surface 2src/renderer/components/agents/PresenceRail.tsx
<CornerOrb/>Surface 2 (collapsed)src/renderer/components/agents/CornerOrb.tsx
<HUDModule/> (bracket-framed card)Surface 3src/renderer/components/agents/HUDModule.tsx
<TeletypeTranscript/>Surfaces 3, 4src/renderer/components/agents/TeletypeTranscript.tsx
<ContinuityBanner/>Surface 3src/renderer/components/agents/ContinuityBanner.tsx
<ProactiveChip/>Surfaces 2, 3src/renderer/components/agents/ProactiveChip.tsx
<FocusTether/> (SVG beam)Surface 3src/renderer/components/agents/FocusTether.tsx
<AgentTabs/> (top-bar chips)Surface 4src/renderer/components/agents/AgentTabs.tsx
<AgentGrid/> (adaptive layout)Surface 4src/renderer/components/agents/AgentGrid.tsx
<SatelliteCluster/> (4-corner)Surface 4 focussrc/renderer/components/agents/SatelliteCluster.tsx

7 · IPC & API Contracts

All new contracts follow the existing pattern: Zod schema in src/contracts/, response envelope { ok: true, data: T } | { ok: false, error: string }, validated at the IPC bridge before handler execution.

New contracts

src/contracts/agent-presence.ts

export const AgentStateSchema = z.enum(['idle','listening','thinking','speaking','muted'])
export const PresenceTierSchema = z.enum(['dashboard','subtle-rail','subtle-orb','war-room-single','war-room-multi','war-room-focus'])

export const AgentPresenceSchema = z.object({
  codename: AgentCodenameSchema,   // existing
  state: AgentStateSchema,
  tier: PresenceTierSchema,
  sessionStart: z.string().datetime(),
  lastTurnAt: z.string().datetime().nullable(),
  thoughtStream: z.string().nullable(),
  activeModule: z.enum(['recall','queue','memory','feeds','context','telemetry']).nullable(),
})

export const ProactiveSuggestionSchema = z.object({
  id: z.string().uuid(),
  codename: AgentCodenameSchema,
  message: z.string(),
  actions: z.array(z.object({
    label: z.string(),
    kind: z.enum(['primary','secondary']),
    commandId: z.string(),
  })),
  expiresAt: z.string().datetime(),
})

src/contracts/agent-hud.ts

export const HUDModuleDataSchema = z.object({
  id: z.enum(['recall','queue','memory','feeds','context','telemetry']),
  title: z.string(),
  mainLine: z.string(),
  subLine: z.string().optional(),
  pills: z.array(z.object({ label: z.string(), tone: z.enum(['neutral','warn','ok','danger','info']) })).optional(),
  serial: z.string().optional(),
  incoming: z.boolean().default(false),
  focused: z.boolean().default(false),
})

export const ToolReadinessSchema = z.object({
  tools: z.array(z.object({
    id: z.enum(['gmail','calendar','commits','memory','draft']),
    state: z.enum(['warm','composing','cold','error']),
    sub: z.string().optional(),
  })),
})

New IPC channels (16 total)

Add to src/contracts/ipc-channels.ts under IPC:

ChannelDirectionPurpose
PRESENCE_GETReq/ResCurrent AgentPresence for named agent
PRESENCE_SET_TIERReq/ResSwitch presence tier (validated allowed transitions)
PRESENCE_UPDATEPushAgent state change pushed from main
PRESENCE_MUTE_TOGGLEReq/ResFlip muted state (war room)
HUD_GET_MODULESReq/ResGet 6 HUD module payloads
HUD_UPDATEPushHUD module data changed (e.g., new inbound)
TOOLS_GET_READINESSReq/ResGet 5-chip tool readiness snapshot
TOOLS_UPDATEPushTool readiness change
PROACTIVE_GET_PENDINGReq/ResCurrent proactive suggestion, if any
PROACTIVE_ACCEPTReq/ResUser accepted suggestion → invoke commandId
PROACTIVE_DISMISSReq/ResUser dismissed
PROACTIVE_NEWPushNew suggestion materialized
THOUGHT_UPDATEPushThought-stream whisper changed
TRANSCRIPT_APPENDPushNew turn appended
CONTINUITY_GETReq/ResBanner text ("picking up from yesterday 18:42 — X")
RAIL_TOGGLE_STATEReq/ResPersist last rail / orb state

Web API (Phase 1.5+)

Mirrors the IPC surface over HTTP for the web PWA. All under /api/agent-presence/*, /api/hud/*, /api/proactive/*, /api/tools/*. Request/response shapes are the same Zod schemas — we export both sides from src/contracts/.

8 · State Machines

Agent state (per agent)

  idle ──(mic detects VAD)──> listening
  listening ──(user stops speaking, agent starts reasoning)──> thinking
  thinking ──(agent starts TTS)──> speaking
  speaking ──(TTS complete, no further turn)──> idle
  {any} ──(mute toggle)──> muted ──(unmute)──> idle

The orb color, halo intensity, ring speed, and thought-stream visibility all derive from this state. listening = atlas-violet halo bright, slow breathing. thinking = karma-orange undertone, turbulent orb. speaking = apex-green accent, ripples project outward. muted = orb dims to 40% opacity, halo hidden, rings static.

Presence tier (per agent)

  dashboard ──(click card)──> war-room-single
  any ──(focus tether click / war-room button)──> war-room-single
  war-room-single ──(navigate away)──> subtle-rail (default) OR subtle-orb (if last was collapsed)
  subtle-rail ──(minimize − button)──> subtle-orb
  subtle-orb ──(tap orb / ⌘\)──> subtle-rail
  subtle-* ──(⌘J / war-room button)──> war-room-single
  war-room-single ──(open multi-route)──> war-room-multi  [Phase 2+]
  war-room-multi ──(click chip)──> war-room-focus
  war-room-focus ──(click ⊞ back)──> war-room-multi

Invalid transitions (e.g., subtle-rail → war-room-multi without going through multi-route entry) are rejected by the presence handler.

9 · Persistence Rules

StateScopeWhere
Last subtle tier (rail/orb)Per user profileatlas_settings KV: ui.presence.lastSubtleTier
Last rail widthPer user profileatlas_settings KV: ui.presence.railWidth
Continuous session startPer agentatlas_conversations.session_start_at
Last turn timestampPer agentatlas_conversations.last_turn_at
Mute stateEphemeral (session only)In-memory; does not persist across app close (safer default)
HUD module focusEphemeralIn-memory
Proactive suggestion queueDurableNew atlas_proactive_suggestions table (Phase 1.6)

Sessions are never explicitly closed. Closing the app suspends them; reopening resumes with the continuity banner (T+18h 23m).

10 · Data Feeds Required

Six feeds must be live and reactive for the war room HUD modules to show real data (vs. placeholder):

  1. Active Recall — memory service emits most-recent-recalled episode(s); target: event on memory search > confidence threshold
  2. Draft Queue — email service emits drafts awaiting approval; target: event on email.draftCreated + email.draftRevised
  3. Memory Trail — memory service emits episode-chain for the current reasoning context (last ~3 pulled)
  4. Live Feeds — inbound email + calendar-event + external-notification stream; fires red-pulse on arrival
  5. Context Threads — commitment/topic service emits the top ~3 active contexts with last-touched timestamps
  6. Voice Telemetry — Pipecat/browser-native voice layer emits VAD level, RTT, cost, mood classification

Feeds 1, 2, 5 exist today. Feeds 3, 4, 6 are new work in Phase 1.6.

11 · Trust & Privacy

The "always-on mic" posture requires explicit, always-visible affordances. Non-negotiable:

  1. Persistent mute pill in the top-right of every war-room surface. Shows unmuted state with a pulsing dot; muted state with a filled pill, distinct color, and MUTED label.
  2. Muted-state orb visual — orb dims, halo removed, rings freeze. Impossible to confuse with unmuted.
  3. System-level indicator parity — on desktop, OS mic indicator (macOS menu bar mic dot) must match our shown state. If OS says mic is live and we say muted, that's a bug.
  4. First-run consent gate — before the war room ever opens, a one-time modal: "Mission Control's war room keeps the mic open for continuous conversation. You can mute anytime (top-right or ⌘M). OK to proceed?"
  5. Subtle presence mic policy — rail + corner orb do NOT keep mic open by default. Mic only engages when user clicks the mic button. (Different posture from war room, which is immersive.)
  6. No stored audio — transcripts are stored (text), raw audio is not.
  7. Draft-first trust contract — no tool call (email send, calendar event create, etc.) fires without user approval. Proactive suggestions chip is suggestion, not action.

12 · Performance Budgets

BudgetTargetNotes
War-room initial render< 400msFrom route navigation to orb visible breathing
Orb animation frame rate60fps on M1+, degrade to 30fps on low powerCSS transform + opacity only
Presence rail → orb collapse< 300ms animatedCSS transform
Focus swap (grid → focus)< 400ms animated cross-fade
Memory-trail SVG redraw< 16msWhen new episode pulled
Transcript append< 50ms from push event to paintVirtualize if > 500 turns

13 · Mobile/PWA Degradation

SurfaceMobile behavior
Dashboard landing1-column stack of agent cards. Shakeeb strip stays full-width.
Subtle railReplaced by bottom sheet (swipe up to expand, swipe down to dismiss). No corner orb on mobile — hit targets are too small.
War room singleStripped variant — orb + state label + transcript. No HUD modules, no tether, no ambient telemetry. Shows "open on desktop for full experience" banner.
War room multiNot available on mobile. Redirects to dashboard with "multi-agent war room is desktop-only."

14 · Accessibility

15 · Test Strategy

LayerCoverage
Unit · Zod contracts100% schema validation cases — valid/invalid/boundary
Unit · Presence state machineAll valid transitions fire, all invalid rejected with specific error
Unit · Components (Vitest + @testing-library/react)Orb renders all 5 codenames · rail collapse → orb transition · focus swap topology change
Integration · IPC handlersAll 16 new channels validated end-to-end with Zod round-trip
E2E · Playwright5 scripts: J1 morning walk-in, J2 email rail, J3 war-room extended, J4 multi-agent swap, J5 mobile PWA degradation
A11y · axe-coreNo violations on any of the 4 surfaces at WCAG AA
Visual regression · Playwright screenshotsSnapshot of each surface at desktop + tablet + mobile widths
Performance · Lighthouse on PWAScore ≥ 90 on each surface

16 · Implementation Phases

Order below is build sequence, not release order. All surfaces except multi-agent land together in Phase 1.6.

Phase 1.6 (now → 4 weeks, single-agent only)

Phase 2 (when BRX lands)

Phase 3 (when Jean Otti, Nadzingo, Kamini land)

17 · Open Questions

  1. 5-agent layout confirmation. Spec ships "hero-top-row + 2×2 quadrant" for 5. User indicated preference for this vs. 3+2 rows vs. 5 equal columns. Confirm before Phase 2 start.
  2. Agent switching in subtle rail. Phase 2+ — does the rail always show the default agent, or does it auto-switch based on what the user is doing? (e.g., viewing a car page in the app → BRX rail)
  3. Proactive suggestion cadence cap. How many proactive chips per hour before it feels naggy? Default proposal: 3/hour max, cooldown of 5min between.
  4. Session-end visualization. If the user goes 48+ hours without interacting, does the continuity banner still say "picking up from 2 days ago at 18:42"? Or does it propose a fresh start? Default: always resume, with option to "start fresh" in the banner.
  5. Mute-state mic icon on PWA. Browsers show their own mic indicator in the tab — can we suppress / layer ours so they don't look contradictory?

18 · Companion Documents

The four HTML design previews, rendered live via Vercel (deployed from /public):

DocURLPurpose
A/B/C directionsdesign-options-voice-shakeeb-2026-04-20.htmlInitial direction pick (voice-A Living Presence)
JARVIS v2 refinementdesign-options-voice-shakeeb-v2-jarvis-2026-04-20.htmlJARVIS-feel single-agent war room
JARVIS v3 density pushdesign-options-voice-shakeeb-v3-push-2026-04-20.htmlFinal war-room single layout — 7 density layers
Agent surfaces v1design-options-agent-surfaces-2026-04-20.htmlLanding, subtle 3-variant pick, multi-agent 2-variant pick
Agent surfaces v2design-options-agent-surfaces-v2-2026-04-20.htmlRefinements — toggle, adaptive grid, focus swap

Related specs + decisions:


Mission Control · Agent Surfaces Spec · v1 · 2026-04-20