Skip to main content
Most dashboards are component museums — a grid of widgets the user navigates between, each demanding attention on its own schedule. The user serves the interface. GenieHelper inverts this. The AI decides what context is relevant. The interface assembles itself around the conversation.

The theatrical model

The UI is built around a theatre metaphor. The audience faces one thing at a time, but the wings and the pit are always alive, ready to deliver. There is no navigation in the traditional sense — the agent opens panels, shifts modes, and updates context cues as the conversation progresses.
┌─────────────────────────────────────────────────────────────────────┐
│  TopCueRail — mission label + mood indicator + platform health       │
├──────────────────┬──────────────────────┬───────────────────────────┤
│                  │                      │                           │
│   LEFT WING      │    CENTER STAGE      │     RIGHT WING            │
│   ToolsSheet     │  CenterStageViewport │    InsightsSheet          │
│                  │                      │                           │
│  Action panels:  │  centerMode:         │  Intelligence panels:     │
│  · vault         │  · chat              │  · live-scrape-feed       │
│  · platform-dock │  · post_draft        │  · analytics-basic        │
│  · media-vault   │  · fan_reply         │  · analytics-advanced     │
│  · mockup        │  · persona_review    │  · idea-radar             │
│  · post-workflow │  · mission_briefing  │  · taxonomy               │
│  · timeline      │  · onboarding        │  · fan-dossier            │
│  · identity      │  · error_recovery    │  · diagnostics            │
│  · sessions      │  · scrape_alert      │  · memory-graph           │
│                  │                      │                           │
│  [collapsed →    │  ← always present,   │  ← appears when agent     │
│   nav rail]      │    mode shifts with  │    surfaces insight]      │
│                  │    conversation]     │                           │
├──────────────────┴──────────────────────┴───────────────────────────┤
│  THE PIT — StickyActionPitDock                                       │
│  Persistent quick actions · skill shortcuts · active job progress    │
│  Collapsed by default · expands on agent request or user pull-up     │
└─────────────────────────────────────────────────────────────────────┘
                     ↑ NavRail (left edge, always present)

Zone responsibilities

ZoneComponentDriven byPurpose
Top RailTopCueRail.jsxmissionLabel + mood stateContext cue — what the agent is working on. Mood shifts color: neutral → active → warning → success
Center StageCenterStageViewport.jsxcenterMode (8 modes)Primary interaction — chat, post drafting, fan reply, onboarding, error recovery, scrape alert
Left WingToolsSheet.jsxleftPanel keyTool panels — what you do (connect, upload, schedule, mockup)
Right WingInsightsSheet.jsxrightPanel keyIntelligence panels — what you know (analytics, taxonomy, fan data, live feeds)
The PitStickyActionPitDock.jsxpitContent + pitExpandedPersistent quick-action dock — collapses to a sliver, expands on demand or agent trigger
Nav RailNavRail.jsxAlways visiblePrimary navigation + left wing collapse toggle

How the agent drives the UI

The user does not navigate to panels. The agent opens them. When a creator sends “scrape my OnlyFans stats”, the following happens without a single click:
1

User sends a message

The creator types “scrape my OnlyFans stats” into the Center Stage chat. The message is sent via POST /api/genie/stream-chat.
2

SSE stream begins

The server opens an SSE stream. The first stage_update event carries { missionLabel: "Scraping OnlyFans...", mood: 'active' }.
3

realtimeEventRouter intercepts

realtimeEventRouter.js receives the event and calls openContext({ missionLabel, mood: 'active' }) on the StageContext reducer.
4

TopCueRail updates

The mission label changes to “Scraping OnlyFans…” and the rail color shifts to amber (active mood) — no user action required.
5

Right Wing opens

A second stage_update event carries { rightPanel: 'live-scrape-feed', rightVisible: true }. The InsightsSheet opens LiveScrapeFeedPanel automatically.
6

Job completes

A final event sets { mood: 'success', missionLabel: "✓ 47 posts scraped" }. The TopCueRail goes green.
No routing. No manual panel management. The conversation produces context; the interface adapts to it. The full routing path: Agent response → SSE event → realtimeEventRouter.jsopenContext()stageReducer → React re-render. No prop drilling. No imperative navigation. The state machine is the UI.

Center mode states

The Center Stage is not a static chat window — it switches modes based on what the agent determines the user needs to do next.
ModeTriggered when
chatDefault — conversational agent interaction
post_draftAgent surfaces a content idea ready to draft and schedule
fan_replyA fan message needs a response — agent pre-drafts it
mission_briefingAgent is starting a multi-step task and surfaces its plan
onboardingNew user with incomplete platform setup
scrape_alertHITL login required — platform blocked headless Chrome
error_recoveryAn action failed and the agent needs human input to recover
persona_reviewIdentity or profile update needs creator confirmation

The 17 panels

Every panel is registered in skillRegistry.js with a left or right slot assignment. The agent references a panel by key; the registry resolves the component and target.
KeyComponentPurpose
vaultConnectionVaultPanelManage platform credentials and API connections
platform-dockPlatformDockPanelLive platform health and session status
mockupMockupStudioPanelPreview post mockups across platform layouts
sessions-consoleSessionsConsolePanelActive browser sessions and HITL queue
media-vaultMediaVaultPanelMedia asset library — upload, browse, manage
identity-studioIdentityStudioPanelCreator persona, voice settings, content boundaries
timelineTimelinePanelEditorial calendar and publish queue
protection-inspectorProtectionInspectorPanelSteganographic watermark verification
post-workflowPostWorkflowPanelPost drafting, scheduling, and variant management
KeyComponentPurpose
live-scrape-feedLiveScrapeFeedPanelReal-time scrape job output and status
analytics-basicAnalyticsBasicPanelRevenue, subscriber count, and engagement summaries
analytics-advancedAnalyticsAdvancedPanelCampaign ROI, platform breakdown, goal progress
idea-radarIdeaRadarPanelAI-scored content ideas from the idea inbox
taxonomyTaxonomyPanelBrowse and search the 3,205-node content taxonomy
fan-dossierFanDossierPanelFull fan profile, memories, scores, and history
diagnosticsDiagnosticsDrawerSystem health, job queue status, error logs
memory-graphMemoryGraphPanelDuckDB skill graph visualization (deferred)
All 17 panels were completed in Sprint 9/10. Panel availability within a session is governed by the creator’s subscription tier — skillRegistry.js includes a tier array per panel entry.

skillRegistry.js — the wiring layer

Every panel is registered in dashboard/src/shared/skillRegistry.js. The registry maps a short key to a component ID and a stageTarget ('left' or 'right'). The agent emits a key in an SSE event; the registry resolves where it goes.
// Excerpt from skillRegistry.js
{
  key: 'live-scrape-feed',
  componentId: 'LiveScrapeFeedPanel',
  stageTarget: 'right',        // → InsightsSheet
  label: 'Live Scrape Feed',
  tier: ['creator', 'pro', 'studio'],
},
{
  key: 'post-workflow',
  componentId: 'PostWorkflowPanel',
  stageTarget: 'left',         // → ToolsSheet
  label: 'Post Workflow',
  tier: ['starter', 'creator', 'pro', 'studio'],
},
The agent never references DOM elements or React components directly. It emits a skill key in an SSE stage_update event. realtimeEventRouter.js reads the key, looks up the registry entry, and calls openContext() with the resolved target. stageReducer handles the rest.
To add a new panel, register it in skillRegistry.js with a unique key, a component ID, a stageTarget, and the tiers that can access it. The Stage system will handle routing automatically.

Mobile: three surfaces, one at a time

On mobile, the three spatial zones collapse into a surface switcher. The agent still drives which surface is active — it is presented as a tab transition instead of a side-by-side layout.
Mobile surface toggle (SurfaceToggle.jsx):
┌──────────┬──────────────┬──────────┐
│  TOOLS   │   CHAT ●     │ INSIGHTS │
│ToolsSheet│ CenterStage  │InsightsSh│
└──────────┴──────────────┴──────────┘
           activeSurface state
When the agent opens a right panel on mobile, activeSurface shifts to 'insights' — the user lands on the insight without navigating. When a left panel opens, activeSurface shifts to 'tools'. The same SSE-driven logic applies; the viewport constraint is the only difference.

Build docs developers (and LLMs) love