diff --git a/docs/consumer/consumer-adaptation-spec.md b/docs/consumer/consumer-adaptation-spec.md index 821067bf..eee4caef 100644 --- a/docs/consumer/consumer-adaptation-spec.md +++ b/docs/consumer/consumer-adaptation-spec.md @@ -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 ``** — 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 `` 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 → POST /api/v1/agents/{id}/run +nebula task get → 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 export type ViewModeContextValue = { mode: ViewMode isSimple: boolean - isStandard: boolean + isPower: boolean isAdvanced: boolean setMode: (mode: ViewMode) => void } -export const ViewModeContext = createContext(...) - export function ViewModeProvider({ children }) { const [mode, setModeState] = useState(getStoredViewMode) - const setMode = (m: ViewMode) => { setModeState(m); setStoredViewMode(m) } - return ( - - {children} - - ) + 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 `` 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 ✓") | ---