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
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:
@@ -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 ✓") |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user