docs: refine 3-mode progressive disclosure spec (Simple/Power/Advanced)
Some checks failed
Stuffle/nebula-os/pipeline/head There was a failure building this commit

- Simple mode: chat-dominant layout, consumer-warm theme skin, ExecutionStrip
  progress panel with plain-English agent states (Thinking, Security check,
  Tool call, Done). Body font switches from JetBrains Mono to Inter via
  [data-mode=simple] CSS block.
- Power mode: current UI curated with exact removal matrix (Plugins, Policies,
  Security Center, Logs, Build Verification, Breakpoints, raw event types).
- Advanced mode: Power + BrowserCLI (xterm.js bottom panel, Ctrl+backtick).
  CLI translates commands to REST API calls - zero server-side subprocess.
- Theme architecture: data-mode on html element, independent of data-theme.
- Add C-030 (theme skin), C-034 (BrowserCLI), C-035 (Power mode audit).
- Fix Section 6 nav model to use Power throughout.
This commit is contained in:
2026-04-08 02:22:11 +05:30
parent 1ff52b0d98
commit 33c9ea9a4e

View File

@@ -150,14 +150,19 @@ The platform is infrastructure-grade. The consumer layer is barely started. The
### 3.2 What Changes with the 3-Mode Model
The mode system is a **runtime user preference** (`localStorage`), not a build-time flag or a separate deployment. The same app renders at different depths based on the user's current mode. The key changes are:
Modes are **skins** — they change layout, content depth, and visual theme simultaneously. The same backend, same data, same routes. Three axes change together when mode switches:
1. **`ViewModeContext`** — new React context wiring mode preference through the component tree
2. **`ViewModeToggle`** — 3-segment pill toggle added to `Navbar.tsx`, always visible
3. **Mode-aware rendering**existing components like `TaskDebugger`, `AgentDetail`, `Agents`, `Settings` switch their rendered layout based on `isSimple / isStandard / isAdvanced`
4. **`ExecutionStrip`** — new component for Simple mode: horizontal compact node progress bar (reuses WS data already flowing to `TaskDebugger`)
5. **`ActivityFeed`** — new component for Standard mode: human-readable event translations (reads same events as current raw Events tab)
6. **`VITE_DEFAULT_VIEW_MODE`** — new env var sets the default mode per deployment; consumer URL defaults `simple`, operator URL defaults `advanced`
1. **Layout**how screen space is divided (chat-dominant vs split vs full-operator)
2. **Content depth**what is shown in that space (progress strip vs compact DAG vs full debugger)
3. **Theme/skin**fonts, color density, border weight, spacing (consumer-warm vs developer-terminal)
The key new pieces:
- **`ViewModeContext`** — React context, `'simple' | 'power' | 'advanced'`, persisted to `localStorage`
- **`ViewModeToggle`** — always-visible 3-segment toggle in Navbar
- **`data-mode` attribute on `<html>`** — CSS selectors handle theme skin switching, decoupled from `data-theme` (dark/light)
- **`ExecutionStrip`** — new Simple mode component: compact horizontal progress panel showing agent states as human-readable labels
- **`BrowserCLI`** — new Advanced mode component: `xterm.js` terminal translating typed commands to REST API calls
- **No new backend endpoints required for Simple/Power** — all data already flows via existing WS and REST APIs
---
@@ -201,119 +206,218 @@ The mode system is a **runtime user preference** (`localStorage`), not a build-t
| **C-025** | Consumer notification system | P3 | Engagement | M | Push/email notifications when long-running agents complete tasks. Uses existing `notifications` router. |
| **C-026** | Agent performance scorecard (consumer view) | P3 | Analytics | M | Simplified view of `Analytics.tsx` for consumers: "Your agents have saved you X hours this week. Cost: $Y." No raw token counts or latency histograms. |
| **C-027** | Consumer-facing API docs | P3 | Developer | M | If/when we open the API: simplified getting-started guide. Not the full OpenAPI spec. Target: someone who wants to automate via API without understanding NebulaOS internals. |
| **C-028** | `ViewModeContext` + `ViewModeProvider` | P0 | Mode system | S | Core React context for mode preference. `'simple' \| 'standard' \| 'advanced'`, persisted to `localStorage`. `VITE_DEFAULT_VIEW_MODE` env var sets per-deployment default. Wire into `Layout.tsx` above `HelpContext`. |
| **C-029** | `ViewModeToggle` component in Navbar | P0 | Mode system | S | 3-segment pill toggle (Sparkles/Layers/Bug icons). Placed top-right in `Navbar.tsx` before notification bell. Icon-only on mobile, icon+label on desktop. Reads/writes `ViewModeContext`. |
| **C-030** | `ExecutionStrip` component (Simple mode) | P0 | Mode system | M | Compact horizontal node progress strip for `/tasks/:id` in Simple mode. Reuses existing WS data from `useTaskDebugWS`. Nodes shown as lettered dots with step name below, pulsing while active, color per status. No IDs, no event types. Sits below the output result area. |
| **C-031** | `ActivityFeed` component (Standard mode) | P1 | Mode system | M | Human-readable event translation feed for `/tasks/:id` in Standard mode. Reads same `ApiExecutionEvent[]` as current Events tab. Translates: `tool_called` → "Called [tool_name]", `node_completed` → "Completed [step name]", `llm_response` → "Generated response". Hides `policy_checked`, `heartbeat`, `llm_trace` categories. Duration + cost footer. |
| **C-032** | Mode-aware `TaskDebugger` routing | P1 | Mode system | M | `/tasks/:id` renders `SimpleTaskResult` (output + `ExecutionStrip`) when `isSimple`, `StandardTaskView` (compact DAG + `ActivityFeed`) when `isStandard`, current full `TaskDebugger` when `isAdvanced`. Same data fetches for all three — only rendering depth differs. |
| **C-033** | Mode-aware `AgentDetail` + `Agents` + `Settings` | P1 | Mode system | L | `AgentDetail`: Simple = `RunGoalForm` full-width + status pill only. Standard = RunGoalForm + compact stats + corpus selector. Advanced = current full page. `Agents`: Simple = card grid, Standard = card+table toggle (current), Advanced = table. `Settings`: Simple = 2 tabs (AI + Account), Advanced = all tabs. |
| **C-028** | `ViewModeContext` + `ViewModeProvider` | P0 | Mode system | S | Core React context for mode preference. `'simple' \| 'power' \| 'advanced'`, persisted to `localStorage`. Sets `data-mode` on `<html>` for CSS skin switching. Wire into `Layout.tsx` above `HelpContext`. `VITE_DEFAULT_VIEW_MODE` sets default. |
| **C-029** | `ViewModeToggle` component in Navbar | P0 | Mode system | S | 3-segment pill toggle (Sparkles / Layers / Terminal icons). Top-right in `Navbar.tsx`, before notification bell. Icon-only mobile, icon+label desktop. Reads/writes `ViewModeContext`. |
| **C-030** | Simple mode theme skin (`[data-mode="simple"]` CSS block) | P0 | Mode system / Theme | S | Add `[data-mode="simple"]` block to `index.css`. Key overrides: body font → `var(--font-sans)` (Inter), desaturated neons, softer backgrounds, no glow shadows, more padding. This is the highest-leverage single change — transforms the entire feel. |
| **C-031** | `ExecutionStrip` component (Simple mode progress panel) | P0 | Mode system | M | Plain-English agent state display for Simple mode. Reads `ApiExecutionEvent[]` from `useTaskDebugWS`. Maps event types to human labels: `llm_request` → "Thinking…", `plan` node completed → "Plan created", `policy_checked` → "Security check ✓", `tool_called` → "Tool call: [name]", `task_completed` → "Done ✓". Horizontal pill sequence, animated. |
| **C-032** | `ActivityFeed` component (Power mode events panel) | P1 | Mode system | M | Human-readable event translation for Power mode right panel. Replaces raw Events tab. Same `ApiExecutionEvent[]` source. Translates: `tool_called` → "Called [tool name]", `node_completed` → "[Step name] complete", `llm_response` → "Generated response". Hides `policy_checked`, `heartbeat`, `llm_trace`, `security_*` event categories. Duration + cost footer. |
| **C-033** | Mode-aware rendering: `TaskDebugger`, `AgentDetail`, `Agents`, `Settings`, `Navbar` | P1 | Mode system | L | Wire `useViewMode()` into each component. `TaskDebugger`: Simple=`ExecutionStrip`+output, Power=DAG+`ActivityFeed`, Advanced=current. `AgentDetail`: Simple=RunGoalForm only, Power=+stats+corpus, Advanced=full. `Agents`: Simple=card grid, Power=current, Advanced=current. `Settings`: Simple=2 tabs, Advanced=all. `Navbar`: filter nav items per mode per Section 5.2 removal matrix. |
| **C-034** | `BrowserCLI` component (Advanced mode) | P2 | Mode system / CLI | XL | `xterm.js` bottom panel (collapsible, `Ctrl+\`` toggle). Command parser maps typed commands to REST API calls — no server-side subprocess. Supported commands: `agent list/get/run/stop`, `task get/cancel`, `plugin list/install`, `workflow list/run`, `logs tail`. IAM JWT attached to every call. Output rendered in terminal with color (ANSI). |
| **C-035** | Power mode nav audit: verify exact removal list with product | P0 | Mode system | XS | The removal matrix in Section 5.2 must be reviewed and signed off before implementing C-033. Items marked "Remove in Power?" are proposals — a product decision, not an engineering decision. |
---
## 5. Architecture — Progressive Disclosure Model (3 Modes)
> **This section supersedes any earlier dual-portal / `VITE_APP_MODE=consumer|operator` framing.** The correct model is a single product with a runtime user-preference dial. Two separate portals is a maintenance trap; two marketing domains on one codebase is fine.
> Modes are **skins**: they change layout, content depth, and visual theme simultaneously. Same backend. Same routes. Same data. Three things change in lockstep when mode switches: **layout**, **content depth**, **theme skin**.
### 5.1 The Core Insight
The previous approach proposed two separate React deployments. That is wrong for one reason: **the execution graph is NebulaOS's core differentiator and should never be fully hidden** — it should be calibrated. The graph is what makes Nebula not ChatGPT. In Simple mode it's a glanceable 3-node horizontal strip below the output. In Advanced mode it's the full ReactFlow canvas with breakpoints. The data feeding both is identical — only the rendering depth changes.
The correct model: **one product, one URL, one codebase — with a 3-position mode dial** that controls layout proportions, visible panels, and terminology depth. Mode is a runtime user preference stored in `localStorage`, not a build-time deployment flag.
### 5.2 The Three Modes
### 5.1 The Three Modes — Precise Definitions
#### Mode 1 — Simple
*Target user: first-time, non-technical, mobile user, or anyone who just wants the answer.*
*Chat interface. Consumer-warm theme. Progress panel shows agent states, not DAG.*
The defining principle: **the chat window dominates**. The entire screen is organised around the input and output. Execution visibility is a dedicated but compact panel — not a sidebar, not a modal — that shows human-readable agent states live as they happen. The theme switches to a consumer skin: `Inter` sans-serif body, softer backgrounds, no neon glows, warmer borders.
```
──────────────────────────────────────────────────────┐
│ [Navbar — minimal: Home / My Agents / Settings]
──────────────────────────────────────────────────────┤
What do you want your agent to do?
│ ┌──────────────────────────────────────────────┐
Give this agent a goal… [Run]
└──────────────────────────────────────────────┘
── Output ──────────────────────────────────────
[Full width result area — output is the star]
│ ── What happened ──────────────────────────────
│ [●]─────[●]─────[●]─────[●] ← execution strip
Plan Search Analyse Done ← compact labels
└──────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ [Slim Navbar — Home / My Agents / ···] [mode: ◉ ○ ○]
├──────────────────────────────────────────────────────────────┤
┌────────────────────────────────────────────────────────┐
│ │ What do you want your agent to do?
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ Give this agent a goal… [Run] │
└──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────
┌──────────── Output (full width) ───────────────────────┐
│ │
[Result text appears here, streaming] │
└────────────────────────────────────────────────────────┘
│ │
│ ── What's happening ────────────────────────────────── │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ ◉ Thinking… → ✓ Plan created → ◉ Security check │ │
│ │ → ◉ Tool call → ◉ Agent working → ✓ Done │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
```
- **Input**: Full-width goal box. `RunGoalForm` already exists — reuse as-is.
- **Execution strip**: Compact horizontal node progress strip below output. Nodes pulse live via WebSocket. Color-coded by status. No IDs, no event types — just step names and status.
- **Output**: Full-width prominent result area. This is what the user came for.
- **Hidden entirely**: Policy events, breakpoints, node IDs, token counts, raw event log, DAG canvas, latency, cost (shown only on UpgradeWall).
- **Nav items**: Home / My Agents / Settings only.
**Layout:**
- Chat input: full-width, large, prominent
- Output area: full-width, streaming, the focus
- Progress panel: compact fixed-height strip below output. Shows live agent states as plain English labels with status dots. NOT a DAG — a linear/branching pill sequence.
#### Mode 2 — Standard
**Progress panel states (shown live via WS):**
- `Thinking…` (llm_request in flight)
- `Plan created` (plan node completed)
- `Security check ✓` (policy_checked — shown but as trust signal, not technical detail)
- `Tool call: web search` (tool_called — tool name only, no raw event data)
- `Agent spawned` (sub-agent created)
- `Awaiting response…` (llm_request in flight after tool)
- `Done ✓` (task_completed)
*Target user: engaged user who wants to understand what's happening without becoming a developer.*
*Note: showing "Security check ✓" in Simple mode is intentional. It builds trust without exposing policy internals. Users see "protected" as a feature, not noise.*
**Theme — Consumer Skin (`[data-mode="simple"]`):**
- Body font: `Inter` (sans-serif) — the single biggest change. Current `body { font-family: var(--font-mono) }` in `index.css:223` makes the entire app feel like a terminal. Simple mode overrides this.
- Background: warmer, slightly lighter dark (`#0d0d14` → `#111118`) — less void-like
- Accent colors: desaturated neons. `--nbl-green: #00ff88` → `#34d399`. `--nbl-cyan: #00d4ff` → `#38bdf8`. Still colored, not flat, but not blinding.
- Borders: slightly heavier weight (`rgba(255,255,255,0.08)` → `rgba(255,255,255,0.11)`) — more defined cards, less floating
- Glow shadows: removed entirely. No `box-shadow: 0 0 28px...` glows in Simple mode.
- Letter spacing: normal (current app has `letter-spacing: 0.04em` on many mono labels — gone in Simple mode)
- Density: more padding in cards and rows. Breathable layout.
**Nav:** Home / My Agents / ··· (overflow: Marketplace, Memory, Settings)
#### Mode 2 — Power
*Current view, deliberately curated. DAG visible. Some operator actions removed.*
The defining principle: **the current product, minus items that require engineering knowledge to use meaningfully**. This is not a new UI — it is a **deliberate surgical removal** of specific nav items, actions, and panels that have no value for a non-operator user. The theme stays dark/neon (developer-comfortable). Layout stays the same.
```
┌──────────────────────────────────────────────────────────────────┐
│ [Navbar: Home / Agents / Tasks / Memory / Marketplace / ···] │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────┬───────────────────────┐ │
│ │ Execution Graph (read-only DAG) │ Activity Feed │ │
│ Compact ReactFlow, no controls │ "Searched the web" │ │
│ Nodes light up as they run │ "Read 2 files" │ │
│ Click node for output │ "Generated draft" │ │
│ │ Duration: 42s · $0.01│ │
├──────────────────────────────────┴───────────────────────┤ │
│ Goal input [full-width] [Run] │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
[Current layout — unchanged]
Left: ReactFlow DAG canvas (read-only in task view, controls in agent view)
Right: Activity panel — simplified Events tab (human-readable translations)
Nav: Dashboard / Agents / Tasks / Workflows / Memory / Marketplace / ···
Removed from current nav/UI:
✗ Plugins (internal capability management — operator only)
✗ Policies (zero-trust configuration — operator only)
✗ Security Center (CVE counters — operator only)
✗ Build Verification (CI integrity checks — operator only)
✗ Logs (raw structured JSON feed — operator only)
✗ Breakpoints in TaskDebugger (step/resume controls)
✗ Raw event types in Events tab (policy_checked, llm_trace, heartbeat, etc.)
✗ Node ID / ULID display
✗ "Publish plugin" modal in Marketplace
```
- **Execution graph**: Compact ReactFlow canvas (left, ~60% width). Read-only — no breakpoints, no step controls. Nodes animate as they run. Click a node to see its output inline.
- **Activity feed** (right, ~40% width): Human-readable translations of events. NOT raw event types — translated strings: "Searched the web 3 times", "Called GitHub API", "Wrote 800 words". Built by translating `tool_called` / `node_completed` events.
- **Cost + duration**: Visible. Consumers who are paying for BYOAI care about this.
- **Hidden**: Raw event types (`policy_checked`, `tool_authorization_verdict`, `llm_trace`), node IDs, breakpoints, step/resume controls.
- **Nav items**: Home / Agents / Tasks / Memory / Marketplace / Settings.
**What Power mode KEEPS from current UI:**
- Full ReactFlow DAG — readonly execution graph, same as current
- Events tab: translated to human-readable ("Called web search", "Generated response") — raw event types hidden
- Cost and duration display
- Workflows
- Knowledge Base / RAG corpora
- Integrations
- Analytics (simplified view)
- Marketplace browse (no publish)
- Context Bank / Memory
- Approvals (consumers may need to approve agent actions)
**Theme:** unchanged — dark/neon developer skin. Power users are comfortable with it.
**Critical design decision for Power mode:** The items to remove must be explicitly enumerated and agreed before implementation. "Some of the actions/menu items removed" is not specific enough for a dev ticket. See Section 5.3 for the exact removal matrix.
#### Mode 3 — Advanced
*Target user: developer, operator, power user who wants full observability.*
*Full operator view + browser-embedded CLI terminal.*
The defining principle: **everything in Power mode, plus a browser CLI panel** that gives operators direct command-line access to the Nebula runtime without leaving the browser. This is the developer and operator mode.
```
[Current TaskDebugger layout — unchanged]
Left: ReactFlow canvas with node selection, breakpoints, step controls
Right: Tab panel — Events / Breakpoints / Resources / Node Detail
Bottom: Execution timeline strip
Stats: Total / Completed / Running / Pending / Failed / Breakpoints
┌─────────────────────────────────────────────────────────────────┐
│ [Full nav: Dashboard / Agents / Tasks / Workflows / ···] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [Current full UI — TaskDebugger, all panels, all controls] │
│ │
├────────────────── CLI Panel (collapsible, bottom) ──────────────┤
│ nebula agent list │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ agent_01H8YZR3T2A9C autoblogger running │ │
│ │ agent_01H8YZR4Q1XXF security-check idle │ │
│ └──────────────────────────────────────────────────────────┘ │
│ nebula █ │
└─────────────────────────────────────────────────────────────────┘
```
This is the current product, unchanged. The `TaskDebugger` at `/tasks/:id` already implements this fully.
**CLI Panel design:**
- `xterm.js` — industry standard browser terminal (used by VS Code, GitHub Codespaces, Replit). Renders a real terminal with cursor, colors, keyboard shortcuts.
- Collapsible: default collapsed, toggleable via keyboard shortcut (`` Ctrl+` ``) or a "Terminal" button in the Navbar.
- Positioned as a bottom panel (like VS Code's integrated terminal) — does not replace the main content area.
- All panels visible: Events (raw), Breakpoints, Resources, Node Detail with input/output JSON
- Policy events visible: `policy_checked`, `security_check_passed`, `tool_authorization_verdict`
- Step / Resume controls visible
- LLM trace visible: `llm_request`, `llm_response`, token counts
- Full nav: Dashboard / Agents / Tasks / Workflows / Plugins / Policies / ···
**CLI implementation — the safe path:**
The existing `cli/nebula.py` is a Python script that calls the REST API. The browser CLI does the same thing — but directly, without subprocess execution. The frontend translates typed commands to REST API calls:
```
nebula agent list → GET /api/v1/agents
nebula agent run <id> → POST /api/v1/agents/{id}/run
nebula task get <id> → GET /api/v1/tasks/{id}
nebula plugin install → POST /api/v1/plugins
nebula logs tail → SSE /api/v1/logs/stream
```
This means: **zero shell execution on the server**. No subprocess, no bash, no security surface for injection. The CLI is a frontend-only command parser that calls the same authenticated REST API the UI already uses. The IAM JWT is attached to every call — the same auth that protects the REST API protects the CLI.
**Security considerations for Advanced/CLI mode:**
- IAM-gated: CLI panel only renders when `isAdvanced` — not accessible in Simple or Power mode
- No shell passthrough: command parser is a whitelist of known commands, not `exec()`
- No filesystem access: all commands are API calls, no raw file reads/writes
- Rate-limited: same `RateLimitMiddleware` that protects the API applies to CLI API calls
- Audit logged: every CLI command becomes a tagged API call — logged by the existing observability system with `correlation_id`
- No sandboxing needed: because there is no server-side execution, sandboxing is moot
**Theme:** unchanged — dark/neon/monospace. Advanced users chose this mode precisely because they want the terminal feel.
### 5.2 Power Mode — Exact Removal Matrix
This is the deliberate spec that was missing. Every removal must be a conscious decision.
| Item | Current location | Remove in Power? | Rationale |
|------|-----------------|------------------|-----------|
| Plugins nav item | Primary nav | ✅ Yes | Plugin management = operator concern |
| Policies nav item | Primary nav | ✅ Yes | Zero-trust config = operator concern |
| Security Center | Overflow nav | ✅ Yes | CVE counters = infra concern |
| Build Verification | Overflow nav | ✅ Yes | CI/deploy = operator concern |
| Logs | Overflow nav | ✅ Yes | Raw JSON log feed = operator concern |
| Breakpoints tab | TaskDebugger right panel | ✅ Yes | Step debugging = developer concern |
| Step / Resume controls | TaskDebugger toolbar | ✅ Yes | Execution control = developer concern |
| Raw event types | Events tab | ✅ Yes (translate) | Replace with human-readable ActivityFeed |
| Node ID / ULID display | TaskDebugger nodes | ✅ Yes | Node names only |
| LLM trace events | Events tab | ✅ Yes | `llm_request`/`llm_response` hidden |
| Publish Plugin | Marketplace | ✅ Yes | Developer workflow |
| Feature Catalogue `/features` | Nav (if shown) | ✅ Yes | Engineering-internal page |
| CLI panel | Advanced only | ✅ Yes (not shown) | Power users don't need CLI |
| Dashboard | Primary nav | ❌ Keep | Useful summary view for all |
| Workflows | Primary nav | ❌ Keep | Power users can build workflows |
| Analytics | Overflow nav | ❌ Keep (simplified) | Cost visibility matters |
| Integrations | Overflow nav | ❌ Keep | Power users connect services |
| Knowledge Base | Overflow nav | ❌ Keep | RAG corpora are user-facing |
| Approvals | Overflow nav | ❌ Keep | Users need to approve agent actions |
| Context Bank | Overflow nav | ❌ Keep (rename: Memory) | Core user feature |
| Marketplace browse | Overflow nav | ❌ Keep | Community discovery |
| Q&A / Blog | Community nav | ❌ Keep | Community stays accessible |
### 5.3 Mode Selector — Implementation Architecture
```ts
// webapp/src/config/viewMode.ts
export type ViewMode = 'simple' | 'standard' | 'advanced'
export type ViewMode = 'simple' | 'power' | 'advanced'
const STORAGE_KEY = 'nebula_view_mode'
export const DEFAULT_VIEW_MODE: ViewMode =
(import.meta.env.VITE_DEFAULT_VIEW_MODE as ViewMode) ?? 'standard'
(import.meta.env.VITE_DEFAULT_VIEW_MODE as ViewMode) ?? 'power'
export function getStoredViewMode(): ViewMode {
const stored = localStorage.getItem(STORAGE_KEY)
if (stored === 'simple' || stored === 'standard' || stored === 'advanced') return stored
if (stored === 'simple' || stored === 'power' || stored === 'advanced') return stored
return DEFAULT_VIEW_MODE
}
@@ -323,79 +427,113 @@ export function setStoredViewMode(mode: ViewMode) {
```
```ts
// webapp/src/context/ViewModeContext.tsx
// webapp/src/context/ViewModeContext.tsx — also sets data-mode on <html>
export type ViewModeContextValue = {
mode: ViewMode
isSimple: boolean
isStandard: boolean
isPower: boolean
isAdvanced: boolean
setMode: (mode: ViewMode) => void
}
export const ViewModeContext = createContext<ViewModeContextValue>(...)
export function ViewModeProvider({ children }) {
const [mode, setModeState] = useState<ViewMode>(getStoredViewMode)
const setMode = (m: ViewMode) => { setModeState(m); setStoredViewMode(m) }
return (
<ViewModeContext.Provider value={{
mode,
isSimple: mode === 'simple',
isStandard: mode === 'standard',
isAdvanced: mode === 'advanced',
setMode,
}}>
{children}
</ViewModeContext.Provider>
)
const setMode = (m: ViewMode) => {
setModeState(m)
setStoredViewMode(m)
document.documentElement.setAttribute('data-mode', m) // CSS skin switching
}
useEffect(() => {
document.documentElement.setAttribute('data-mode', mode)
}, [])
// ...
}
```
### 5.4 Mode Toggle — Placement and Design
### 5.4 Theme Skin Architecture
- **Location**: Navbar, top-right corner, to the left of the notification bell. Always visible.
- **Design**: 3-segment pill toggle. Icons only on mobile (no labels). Labels on desktop.
- Simple: `Sparkles` icon + "Simple"
- Standard: `Layers` icon + "Standard"
- Advanced: `Bug` icon + "Advanced" (Bug icon already imported in TaskDebugger)
- **Persistence**: `localStorage` — survives page refresh, respects user intent.
- **Default**: Driven by `VITE_DEFAULT_VIEW_MODE` env var. Consumer deployment (`nebula.stuffle.ai`) defaults to `simple`. Operator deployment (`dev.stuffle.ai`) defaults to `advanced`. Users can always change.
- **No lock-in**: Any user can switch to any mode at any time. It's a preference, not an access gate.
The existing CSS is purpose-built for this. Every value is already a `--nbl-*` variable. A `[data-mode="simple"]` block in `index.css` overrides only the tokens that differ — without touching any component styles.
### 5.5 Domain Strategy (Revised)
**The single highest-impact change:** `body { font-family: var(--font-mono) }` at `index.css:223`. The entire app currently renders in `JetBrains Mono`. Overriding this in Simple mode transforms the feel instantly:
The mode model changes what the dual-domain strategy is *for*. It's now purely a **marketing and defaults** decision, not a codebase decision.
```css
/* index.css — add after existing [data-theme="light"] block */
```
nebula.stuffle.ai → same build, VITE_DEFAULT_VIEW_MODE=simple
consumer-facing landing page (LandingConsumer.tsx)
user signs up → starts in Simple mode
[data-mode="simple"] body,
[data-mode="simple"] button,
[data-mode="simple"] input,
[data-mode="simple"] select,
[data-mode="simple"] textarea {
font-family: var(--font-sans); /* Inter — already loaded in @theme block */
}
dev.stuffle.ai → same build, VITE_DEFAULT_VIEW_MODE=advanced
current developer landing page (Landing.tsx)
operator signs up → starts in Advanced mode
[data-mode="simple"] {
/* Softer backgrounds — less void-like */
--nbl-bg: #111118;
--nbl-bg-page: #111118;
--nbl-surface: #1a1a28;
--nbl-bg-surface: #1a1a28;
--nbl-surface-raised: #22223a;
Both → same backend API (nebula.armco.dev)
Both → same auth (Armco IAM)
Both → same DB, same runtime, same agents
/* Desaturated neons — still colored, not blinding */
--nbl-green: #34d399; /* was #00ff88 — emerald vs neon */
--nbl-cyan: #38bdf8; /* was #00d4ff — sky vs electric */
--nbl-amber: #fbbf24; /* was #ffb800 — warm amber */
--nbl-red: #f87171; /* was #ff4757 — soft red */
--nbl-purple: #c084fc; /* was #a855f7 — lighter purple */
/* Slightly heavier borders — more defined cards */
--nbl-border: rgba(255,255,255,0.11);
--nbl-border-subtle: rgba(255,255,255,0.07);
/* Remove glow shadows */
--nbl-glow-green: none;
--nbl-glow-cyan: none;
--nbl-glow-purple: none;
--nbl-glow-amber: none;
--nbl-glow-red: none;
}
```
This is a **2-line nginx difference** (different `VITE_DEFAULT_VIEW_MODE` env vars), not two codebases. Zero maintenance overhead. Users who sign up via the consumer URL start in Simple mode but can graduate to Advanced on their own terms.
**Theme coupling rule:** Mode and theme (dark/light) are independent. `data-mode` handles skin depth. `data-theme` handles dark/light. A Simple mode user can still toggle dark/light. An Advanced mode user in light theme keeps Advanced layout. The CSS cascade handles the combination: `[data-mode="simple"][data-theme="light"]` — both block's overrides apply in order.
### 5.6 What Mode Changes — Concrete Component Map
### 5.5 Mode Toggle — Placement and Design
| Component | Simple | Standard | Advanced |
|-----------|--------|----------|----------|
| `TaskDebugger` graph | Hidden (replaced by `ExecutionStrip`) | Compact ReactFlow, read-only, no controls | Full ReactFlow + breakpoints + step/resume |
| `TaskDebugger` right panel | Hidden | `ActivityFeed` (translated events) | Current tab panel (Events/Breakpoints/Resources/Node Detail) |
| `TaskDebugger` timeline | Hidden | Hidden | Visible |
| `AgentDetail` | Only `RunGoalForm` + status | RunGoalForm + compact stats + corpus | Full: RunGoalForm + stats + permissions + system prompt + corpus + edit |
| `Navbar` items | Home / My Agents / Settings | Home / Agents / Tasks / Memory / Marketplace / Settings | Full current nav |
| `Settings` tabs | AI Provider + Account | AI Provider + Account + Integrations | All tabs |
| Terminology | "Create agent" / "Run" / "Memory" / "Extensions" | "Agent" / "Task" / "Context Bank" / "Plugin" | Technical terms unchanged |
| Cost display | Hidden (only on UpgradeWall) | Shown: "$0.01 · 42s" | Full token/latency analytics |
| Policy events in feed | Hidden | Hidden (abstracted away) | Visible as `policy_checked` entries |
| Node IDs / ULIDs | Hidden (show name only) | Hidden | Visible (truncated via `truncateId`) |
- **Location**: Navbar, top-right, left of notification bell. Always visible in all modes.
- **Design**: 3-segment pill toggle.
- Simple: `Sparkles` icon + "Simple" (label on desktop, icon-only on mobile)
- Power: `Layers` icon + "Power"
- Advanced: `Terminal` icon + "Advanced"
- **Transition**: When switching to Simple, `data-mode` changes on `<html>` immediately → CSS transitions on color and font apply via standard `transition` rules. No React re-render needed for theme — only for layout changes.
- **No lock-in**: Any user, any time. Preference, not access gate.
### 5.6 Domain Strategy (Single Domain)
No second domain is needed. One URL, one build, mode toggle visible to all users. The `VITE_DEFAULT_VIEW_MODE` env var sets the starting mode for first-time visitors — that's the only deployment-level difference that matters.
If a consumer-facing landing page at a separate domain is desired later (purely for marketing), it is a 2-line nginx config pointing to the same build with `VITE_DEFAULT_VIEW_MODE=simple`. That is a future decision, not a prerequisite.
### 5.7 What Mode Changes — Concrete Component Map
| Component | Simple | Power | Advanced |
|-----------|--------|-------|----------|
| **Theme** | Consumer skin: Inter font, soft neons, no glows, more padding | Current dark/neon — unchanged | Current dark/neon — unchanged |
| **Body font** | `Inter` (sans-serif) | `JetBrains Mono` (current) | `JetBrains Mono` (current) |
| **Progress display** | `ExecutionStrip`: plain-English states ("Thinking…", "Security check ✓", "Tool call: web search") | Compact read-only DAG + `ActivityFeed` (translated events) | Full `TaskDebugger`: ReactFlow + Events/Breakpoints/Resources tabs |
| **CLI panel** | Hidden | Hidden | `BrowserCLI`: `xterm.js` bottom panel, REST API-backed |
| **Nav items** | Home / My Agents / ··· | Dashboard / Agents / Tasks / Workflows / Memory / Marketplace / ··· | Full current nav (all items) |
| **Plugins nav** | Hidden | Hidden | Visible |
| **Policies nav** | Hidden | Hidden | Visible |
| **Security Center** | Hidden | Hidden | Visible |
| **Logs** | Hidden | Hidden | Visible |
| **Build Verification** | Hidden | Hidden | Visible |
| **Breakpoints** | Hidden | Hidden | Visible |
| **Raw event types** | Hidden | Hidden (translated) | Visible as-is |
| **Node IDs / ULIDs** | Hidden | Hidden | Visible |
| **Cost display** | Hidden (UpgradeWall only) | Visible ("$0.01 · 42s") | Full analytics |
| **`AgentDetail`** | `RunGoalForm` full-width + status only | RunGoalForm + stats + corpus | Full current page |
| **`Settings` tabs** | AI Provider + Account | + Integrations + Models | All tabs |
| **`Agents` view** | Card grid | Card+table toggle (current) | Full table (current) |
---
@@ -404,39 +542,40 @@ This is a **2-line nginx difference** (different `VITE_DEFAULT_VIEW_MODE` env va
### 6.1 Nav Items by Mode
```
Simple: [Home] [My Agents] [···] [Settings]
Standard: [Home] [Agents] [Tasks] [Memory] [Marketplace] [···] [Settings]
Simple: [Home] [My Agents] [···] [Settings]
Power: [Dashboard] [Agents] [Tasks] [Workflows] [Memory] [···] [Settings]
Advanced: [Dashboard] [Agents] [Tasks] [Workflows] [Plugins] [Policies] [···]
```
The `···` overflow menu (already exists in `Navbar.tsx` as `MoreHorizontal` button) contains mode-appropriate overflow items. In Simple mode: Marketplace, Blog. In Advanced: Knowledge Base, Analytics, Security Center, Logs, Build.
The `···` overflow menu (already exists in `Navbar.tsx` as `MoreHorizontal` button) contains mode-appropriate overflow items. In Simple mode: Marketplace, Memory, Blog. In Power: Integrations, Knowledge Base, Analytics, Marketplace, Approvals. In Advanced: all items including Security Center, Logs, Build Verification.
### 6.2 Route Mapping (unchanged — no new routes needed for mode changes)
Mode changes affect **what is rendered inside** existing routes, not the routes themselves. A Simple-mode user navigating to `/tasks/:id` sees `ExecutionStrip` + output. An Advanced-mode user sees the full `TaskDebugger`. Same URL. Same data fetch. Different rendering depth.
| Route | Simple renders | Standard renders | Advanced renders |
|-------|---------------|------------------|-----------------|
| `/tasks/:id` | `SimpleTaskResult` — output + `ExecutionStrip` | `StandardTaskView`compact DAG + `ActivityFeed` + output | Full `TaskDebugger` (current) |
| `/agents/:id` | `RunGoalForm` full-width + status pill | Agent card + run form + compact stats | Full `AgentDetail` (current) |
| `/agents` | Card grid, name + last run status + Run button | Table + cards toggle (current) | Full `Agents` table (current) |
| `/settings` | AI Provider tab + Account tab only | AI Provider + Account + Integrations | All tabs (current) |
| Route | Simple renders | Power renders | Advanced renders |
|-------|---------------|---------------|------------------|
| `/tasks/:id` | `SimpleTaskResult` — output + `ExecutionStrip` | `PowerTaskView` — full DAG (read-only) + `ActivityFeed` | Full `TaskDebugger` (current, all panels) |
| `/agents/:id` | `RunGoalForm` full-width + status pill only | Current `AgentDetail` minus breakpoints/raw events | Full `AgentDetail` (current) |
| `/agents` | Card grid, name + last run + Run button | Current `Agents` table (unchanged) | Current `Agents` table (unchanged) |
| `/settings` | AI Provider + Account tabs only | AI Provider + Account + Integrations + Models | All tabs (current) |
### 6.3 Terminology Translation by Mode
| Advanced Term | Standard Term | Simple Term |
|--------------|---------------|-------------|
| Advanced Term | Power Term | Simple Term |
|--------------|------------|-------------|
| Spawn Agent | Create Agent | Create Agent |
| Submit task | Run | Run / Ask |
| DAG execution | Execution graph | (hidden — shown as strip) |
| Context Bank | Agent Memory | Memory |
| Submit task | Run task | Run / Ask |
| DAG execution | Execution graph | (hidden — shown as `ExecutionStrip`) |
| Context Bank | Memory | Memory |
| System prompt | Agent instructions | Instructions |
| Plugin | Plugin | Extension |
| Policy | (hidden) | (hidden) |
| Tool call | Action | (hidden — translated to "Searched…", "Read…") |
| Tool call | Action (translated) | (hidden — shown as "Thinking…", "Security check ✓") |
| Corpus | Knowledge Base | Knowledge |
| Breakpoint | (hidden) | (hidden) |
| `policy_checked` event | (hidden) | (hidden) |
| `policy_checked` event | (hidden in feed) | (shown as "Security check ✓" trust signal) |
| `llm_request` / `llm_response` | (hidden) | (shown as "Thinking…" / "Done ✓") |
---