Files
waggle-os/docs/ux-disclosure-levels.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

339 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UX Disclosure Levels — Source-of-Truth Spec
> **Status:** DRAFT r2 — generated by `/plan-design-review` 2026-05-07.
> r1 was the wrong direction (assumed flat sidebar layout). r2 documents the actual live UI: Mac-OS-style desktop with bottom dock + windowed apps. Approval pending.
> Drives: Phase 4.1 polish-sprint scope (filter onboarding to match existing dock-tier filtering) + Phase 4.2 PersonaSwitcher 2-tier work + downstream design polish work.
> Reference plan: `~/.gstack/projects/marolinik-waggle-os/markomarkovic-main-design-20260506-175017.md`
---
## What this is
Waggle OS is a Mac-OS-style desktop running inside a Tauri 2.0 binary. The UI shell consists of:
- **Desktop** (`apps/web/src/components/os/Desktop.tsx`) — full-bleed canvas
- **Bottom dock** (`apps/web/src/components/os/Dock.tsx`) — Mac-OS-style centered floating glass panel with app icons
- **Status bar** (`apps/web/src/components/os/StatusBar.tsx`) — top thin bar
- **Windowed apps** (`apps/web/src/components/os/AppWindow.tsx`) — apps open as draggable, resizable windows
- **Overlays** (`apps/web/src/components/os/overlays/`) — onboarding, persona switcher, workspace switcher, modals
- **Boot screen** (`apps/web/src/components/os/BootScreen.tsx`) — first-launch animation
The 3-level UX disclosure operates at the dock level: the dock filters which apps are visible based on the user's chosen `UserTier` (`simple` / `professional` / `power`), with an additional layer that hides specific entries below their `minBillingTier` (`FREE` / `TRIAL` / `PRO` / `TEAMS` / `ENTERPRISE`).
This spec documents that existing system as canonical and identifies gaps to close before pilot.
## Naming alignment
Three names referenced different things historically:
| Internal enum (`UserTier`) | Display label (TIER_OPTIONS) | Brownfield doc name | This spec |
|---|---|---|---|
| `simple` | Essential | "simple" | **Essential (simple)** |
| `professional` | Standard | "advanced" | **Standard (professional)** |
| `power` | Everything | "pro" | **Everything (power)** |
Plus `admin` (UserTier only) which currently aliases to power's dock config.
Source of truth: `apps/web/src/lib/dock-tiers.ts` (`TIER_DOCK_CONFIG` const). Display labels were renamed in QW-5 to avoid collision with billing tiers (Pro $19, Teams $49). Internal enum values stay `simple/professional/power` for backward compatibility with stored user preferences.
## Default
New user starts at **Essential**. The 8-step onboarding wizard's TierStep (step 3) preselects Essential. Trial users get the same Essential default with reveal moments to Standard. Power is opt-in only via Settings → Display.
---
## Dock contents — already implemented in `dock-tiers.ts`
This is the EXISTING canonical filtering. Spec's job is to document and audit.
### Essential (simple) — 5 dock items (verified)
```typescript
TIER_DOCK_CONFIG.simple = [
{ key: 'home', appId: 'dashboard', icon: LayoutDashboard, label: 'Home', color: 'text-sky-400' },
{ key: 'chat', appId: 'chat', icon: MessageSquare, label: 'Chat', color: 'text-primary' },
{ key: 'files', appId: 'files', icon: FolderOpen, label: 'Files', color: 'text-amber-300' },
{ type: 'separator' },
{ key: 'vault', appId: 'vault', icon: Lock, label: 'Vault', color: 'text-amber-400' },
{ key: 'system', appId: 'settings', icon: Settings, label: 'Settings', color: 'text-muted-foreground' },
]
```
5 items + 1 separator. Memory is NOT in Essential — it's deliberately gated to Standard+ because the discovery moment for "Waggle remembers everything" is the chat surface (where context-restore + login briefing happens), not a separate Memory app.
### Standard (professional) — 7 dock items (verified)
Adds Personas (`agents`) + Memory between Files and Vault. Same 5 from Essential plus:
```typescript
{ key: 'agents', appId: 'agents', icon: Bot, label: 'Personas', color: 'text-orange-400' }, // after chat
{ key: 'memory', appId: 'memory', icon: Brain, label: 'Memory', color: 'text-amber-300' }, // after separator
```
### Everything (power) — full configuration
Power dock adds Room, Waggle Dance, two zone-parents (Ops + Extend) with collapsible trays, plus Approvals (TEAMS-only) above Vault.
- **Ops zone-parent (tray):** Command Center, Timeline, Usage & Cost, Events & Logs, Scheduled Jobs
- **Extend zone-parent (tray):** Skills & Apps, Connectors, Team Governance (TEAMS-only)
- Plus Approvals (TEAMS-only)
Marketplace is a TAB inside Skills & Apps (per P31 comment), not a separate dock item — the spec leaves it that way.
### Billing tier filtering layer
Per-entry `minBillingTier` runs ON TOP of UserTier filtering. Examples already in code:
- `governance` requires `TEAMS`
- `approvals` requires `TEAMS`
Phase 4.1 may need to add `minBillingTier: 'PRO'` to dock entries for Pro-only features (skills marketplace? custom personas? — TBD per Open Q1 below).
---
## Onboarding wizard — 8 steps already exist (audit)
Files: `apps/web/src/components/os/overlays/onboarding/{Welcome, WhyWaggle, Tier, Import, Template, Persona, ApiKey, Ready}Step.tsx`
| # | Step | Current behavior | Phase 4.1 audit |
|---|------|------------------|-----------------|
| 1 | welcome | Hero card + brand + CTA | OK |
| 2 | why-waggle | 3 value props: Remembers everything / Workspace-native / Real tools | OK |
| 3 | tier | Pick Essential / Standard / Everything (Essential preselected) | OK — uses TIER_OPTIONS |
| 4 | memory-import | ChatGPT/Claude/Gemini/Perplexity/Cursor/Claude Code import + auto-detect | OK |
| 5 | template | **Currently shows ALL 15 templates** | **GAP — should filter by tier** |
| 6 | persona | **Currently shows ALL 19 onboarding personas via `getPersonasForTemplate()`** | **GAP — should filter by tier** |
| 7 | api-key | Provider + key + vault auto-detect | OK; add Ollama default in Phase 4.1 (Open Q from brownfield doc) |
| 8 | ready | Summary + first-task + open workspace | OK |
The Phase 4.1 unblock is consistency: dock filters to 5 items at Essential, but onboarding template + persona steps show ALL options regardless of tier. That's an internal inconsistency the user feels — they pick Essential at step 3, then step 5 throws 15 templates at them.
### Templates — filter for Essential — 3 of 15
When `selectedTier === 'simple'`, `TemplateStep.tsx` should default to showing 3 templates with a "Show all 15 templates" toggle:
| ID | Display | Why at Essential | Recommended persona |
|---|---|---|---|
| `agency-consulting` | Consulting | Marko's archetype, Ljiljana's role, broadest professional services match | consultant |
| `research-project` | Research Hub | Universally useful (HR research, market research, due diligence) | researcher |
| `blank` | Blank Workspace | Universal escape — any user who doesn't fit a category | general-purpose |
The other 12 templates remain available via "Show all" toggle (no hard gating — users at Essential who want their domain template aren't blocked). Standard and Everything see all 15 by default.
### Personas — filter for Essential — 4 of 22 (matches `tier` field already in code)
`ALL_ONBOARDING_PERSONAS` already declares 3 cohorts via the `tier` field:
- `tier='universal'` (1): general-purpose
- `tier='knowledge'` (4): researcher, writer, analyst, coder
- `tier='domain'` (14): project-manager, executive-assistant, sales-rep, marketer, product-manager-senior, hr-manager, legal-professional, finance-owner, consultant, support-agent, ops-manager, data-engineer, recruiter, creative-director
When `selectedTier === 'simple'`, `PersonaStep.tsx` should show universal + knowledge cohorts (5 personas: general-purpose, researcher, writer, analyst, coder) PLUS the recommended persona for the selected template (e.g. consultant if Consulting selected). `getPersonasForTemplate()` already does the recommended-first ordering — no logic change needed, just filter to universal+knowledge tiers when `selectedTier === 'simple'`.
> **Decision needed (Open Q): coder at Essential — keep or drop?**
> Coder is in `tier='knowledge'` cohort. Marko's quote: *"this is not the target, unless you identify this tool can be useful for coders too, which I don't believe."* Recommend dropping coder from Essential default (drop the `tier='knowledge'` filter to "knowledge minus coder" or rename `coder` to `tier='domain'`). Result: 4 personas at Essential (general-purpose, researcher, writer, analyst) + recommended-from-template.
The other 14 domain personas + 3 hidden meta-personas (planner, verifier, coordinator) stay accessible at Standard+.
`planner`, `verifier`, `coordinator` remain hidden from `ALL_ONBOARDING_PERSONAS` entirely (they're orchestration meta-personas, not user-facing).
---
## Settings app — filter sections per tier
Current state: `SettingsApp.tsx` shows all sections regardless of UserTier. Phase 4.1 adds level filtering.
### Settings at Essential
| Section | Shown |
|---|---|
| Profile | ✅ |
| Models (provider, API key, Ollama on/off) | ✅ |
| Display (theme, level toggle) | ✅ |
| Memory (view-only stats, opt-out delete path) | ✅ |
| Billing/Subscription | ✅ if user is Trial/Pro/Teams |
Hidden at Essential (visible at Standard+): Tools, Skills, Connectors, Personas (manage), MCP servers, Telemetry, Compliance (Everything+), Evolution (Everything+), Vault management (auto-managed at Essential), Team (TEAMS-only).
### Display panel — the level toggle
Level toggle UI: 3-card chooser using existing `TIER_OPTIONS` array. Currently lives in TierStep.tsx for onboarding; Phase 4.1 adds the same chooser to Settings → Display so users can switch level post-onboarding.
---
## Skills + connectors at Essential — personalize, don't cap
> **Reframe (2026-05-08, Marko):** the previous version of this section
> proposed pre-installing only 5 skills + 3 connectors at Essential. That
> framing is wrong. Hiding 13 of 18 skills doesn't simplify — the agent
> already loads all 18 invisibly so the capability ceiling is unchanged
> either way; the user just feels it has less. Hiding 145 of 148
> connectors doesn't simplify — connectors are zero-installed by default
> and only activate on user OAuth, so the configuration burden is identical
> either way; the user just can't find Linear or GitHub when they have
> those accounts. **Capability is never the simplification target.
> Discoverability + first-screen relevance is.**
### Skills (built-in) — all 18 stay loaded
The starter pack at `packages/sdk/src/starter-skills/` ships **18
skills** that are auto-installed on first run by
`packages/server/src/local/routes/skills.ts:54-63`. They are loaded into
the agent regardless of tier. No tier-based gating on the loaded set.
What CAN vary by tier:
- **Display surface** of the skills picker UI (Settings → Skills tab,
marketplace tab visibility) — currently TIER_DOCK_CONFIG already gates
the marketplace dock entry.
- **In-chat skill suggestions** ("Try `draft-memo` for that?") can be
persona-aware so a Coder gets `code-review` and a Consultant gets
`research-synthesis` without scrolling. Implementation: future Phase
4c — chat skill hint surface.
### Connectors (MCP catalog) — all 148 reachable, recommendation per persona
The MCP catalog at `packages/shared/src/mcp-catalog.ts` has **148
connectors** across 14 categories. Default install state: **zero**. Every
connector requires user OAuth.
What changes by **persona** (not by tier): the connector landing surface
inside ConnectorsApp + the optional onboarding "which tools?" step
recommend a primary set of 35 connectors based on the user's chosen
template + persona. Source of truth:
`packages/shared/src/connector-recommendations.ts` + the `recommendConnectors()`
helper. The full 148 stay browseable and searchable at every tier.
Examples (full table in `connector-recommendations.ts`):
| Persona | Primary recommendation |
|---|---|
| consultant | notion-mcp, gdrive-mcp, gmail-mcp, slack-mcp, figma |
| coder | github-mcp, slack-mcp, linear-mcp, sentry, gdrive-mcp |
| sales-rep | hubspot-mcp, salesforce-mcp, slack-mcp, gmail-mcp, notion-mcp |
| analyst | bigquery, postgres, gdrive-mcp, notion-mcp, excel |
| general-purpose / planner / verifier / coordinator | gdrive-mcp, gmail-mcp, notion-mcp (universal defaults) |
Validation: every recommended ID is asserted to exist in the catalog by
`packages/shared/tests/connector-recommendations.test.ts`. A typo'd or
removed connector ID is caught at CI before it ships an empty tile.
### Net effect on the user
- A consultant who picked Essential during onboarding still has **all
148 connectors reachable** via `ConnectorsApp → All`. The first thing
they SEE is just notion / gdrive / gmail / slack / figma — the five
most likely to matter for that role.
- The same consultant on Standard or Everything sees the same 5 first;
the only difference between tiers is which dock items are visible
(chat / files / home / vault / settings + memory + agents at
Standard + ops console + marketplace at Everything). Connector
capability is identical across tiers.
---
## Empty / loading / error / partial states for Essential surfaces
For each of the 5 dock-visible apps at Essential, specify what user sees in non-happy states.
### Home (Dashboard) — Day 1, just after onboarding
- **Empty:** Grid layout with: workspace name + persona name top-left, "What's on your mind?" with chat input placeholder, 3 starter-prompt chips drawn from `TEMPLATES[selected].hint` + persona's `bestFor[0]` example, "Waggle is learning your work" memory hint card. NOT "No items found."
- **Returning user:** WorkspaceBriefing card shows context recap from last session ("Last session: drafted HR policy v3, saved 8 frames").
- **Loading:** subtle skeleton (matches existing chat shimmer pattern from M2-7).
- **Error (memory unavailable):** "Memory layer is initializing. You can start chatting; Waggle will remember once memory is ready." + retry button. NEVER show stack trace at Essential.
### Chat (in-window app)
- **Empty (new conversation):** persona-aware welcome line (e.g. for consultant: "Hi — I'm here for your client work. What are we tackling?") + 3 quick-start chips from persona's `bestFor`.
- **Loading (LLM call in flight):** existing shimmer pattern.
- **Error (API key invalid):** "Looks like the API key needs attention. [Open Settings]" — NOT a 500 stack.
- **Error (LLM rate limit / 429):** "The model is busy. Trying again in 5s..." with retry counter.
- **Error (network down):** "Lost connection. Your message is saved; will retry when back online." + offline indicator.
### Files
- **Empty:** "Drop files here, or browse from your computer." Drag-drop hint + button. (FileUploadZone component already exists.)
- **Loading:** skeleton rows.
- **Error (storage quota):** "You're using X of Y. Free tier supports Z files. [Upgrade]" — visible only when tier is Free + close to quota.
### Vault (Essential)
- **Empty:** "Your API keys live here, encrypted on your device." + "Add a key" button.
- **Editing:** keys masked by default; reveal-on-click with confirmation.
### Settings
- **API key invalid:** inline error on the field, not a modal. "Key looks invalid — try again." + provider docs link.
- **Memory purge confirmation:** double-confirm dialog with "Type DELETE to confirm" pattern (untechnical-but-decisive UX, prevents accidents). Required for pilot data handling per brownfield doc.
- **Level switch (Essential → Standard):** confirmation + "You'll see more apps in your dock. Switch back anytime in Settings → Display."
---
## Responsive + a11y posture
**Day 0 stance:** Desktop-only (Win + Mac). Tauri binary. NO mobile/tablet responsive promises in launch comms. Dock has horizontal scroll fallback at <768px viewports (already implemented per L-01/R-1 comment in `Dock.tsx:72`).
**A11y at Essential — non-negotiable (most already implemented):**
- Existing Esc-to-skip in OnboardingWizard (verified at line 81) — keep
- Existing dock label visibility for new users (`useDockLabels` <20 sessions or <7 days) — keep
- Tab order: status bar → dock → desktop → workspace context
- Focus visible on every interactive element (waggle-theme.css ring tokens)
- 4.5:1 contrast minimum on body text — **light mode currently broken (P0 from brownfield doc)**, must fix in Phase 4.1
- Touch targets: 44px min
- Screen reader landmarks: `<main>` (Desktop), `role="toolbar"` (Dock), `aria-label` per dock entry
- Memory + workspace state announce on switch (`aria-live="polite"`)
---
## Reveal moments — how a user discovers Standard / Everything
Three reveal triggers (least intrusive first):
1. **Tooltip on first attempt to access a hidden feature.** E.g. user tries to spawn a multi-agent group from Chat — sees "Multi-agent groups need Standard. [Try Standard]". Standard switch is one-click + reversible.
2. **Settings → Display level toggle** with `TIER_OPTIONS` chooser — same UI as TierStep in onboarding.
3. **Soft nudge after 7 days of consistent use:** "You've been using Waggle daily. Standard adds Personas + Memory + agent workflows. Try it for 7 days." Dismissible. Once-per-user-lifetime.
Power level is opt-in only — never nudged. User must navigate Settings → Display → Everything explicitly.
---
## What this spec does NOT cover (out of scope)
- Visual mockups of dock + windowed apps — the live UI is the visual reference; downstream `/design-review` runs on the live binary.
- Pixel-level component design — handled by `/design-consultation` (recommend running before Phase 4.1 implementation).
- Marketing-page (apps/www) design — separate spec.
- Tier billing UX (free vs Pro vs Teams) — handled by upgrade modal redesign (Phase 4.1 must-have, separate from level disclosure).
- New apps — this spec only covers filtering existing apps; the 26 existing apps are out of scope for "what to add."
---
## Acceptance criteria
This spec is approved when:
1. Marko reviews and signs off on the named selections (3 templates / 4 personas at Essential) and the Open Q answers.
2. Phase 4.1 implementer has enough specificity to implement: (a) filter `TEMPLATES` in `TemplateStep.tsx` when `tier === 'simple'`, (b) filter `ALL_ONBOARDING_PERSONAS` by `tier` field when `tier === 'simple'`, (c) filter `SettingsApp.tsx` sections per tier, (d) write empty/loading/error copy for the 5 Essential surfaces.
3. Open Questions 1-3 resolved.
## Open Questions
1. **Coder at Essential — keep or drop?** Recommend drop; Marko's quote supports it.
2. ~~**Pre-installed skills exact selection.** 5 listed; confirm or swap.~~ **CLOSED 2026-05-08** — superseded by reframe: all 18 starter skills stay loaded, no tier-based gating. See "Skills + connectors at Essential — personalize, don't cap" above.
3. ~~**Pre-installed connectors selection.** 3 listed; confirm Gmail vs M365 default vs choose-during-onboarding.~~ **CLOSED 2026-05-08** — superseded by `connector-recommendations.ts` (persona-aware primary set, full 148 stay reachable). Gmail vs M365 picker still belongs in onboarding "which tools?" step (Phase 4b).
4. **`minBillingTier` on dock entries — does Pro need any?** E.g. should marketplace marketplace have `minBillingTier: 'PRO'`? Defer to Stripe-products work in Phase 4.1.
5. **Reveal nudge timing — 7 days or session-count-based?** Recommend 7 days based on `useDockLabels` precedent.
## References (live code, not memory)
- Dock + tier config: `apps/web/src/lib/dock-tiers.ts` (`TIER_DOCK_CONFIG`, `getDockForTier`, `BILLING_TIER_ORDER`, `filterByBillingTier`)
- Dock component: `apps/web/src/components/os/Dock.tsx` (renders `getDockForTier(tier, billingTier)`, includes zone-parent tray pattern + horizontal scroll fallback)
- Tier display labels: `apps/web/src/components/os/overlays/onboarding/constants.ts` (`TIER_OPTIONS`)
- Onboarding constants: same file (`TEMPLATES`, `ALL_ONBOARDING_PERSONAS`, `TEMPLATE_PERSONA`, `VALUE_PROPS`, `getPersonasForTemplate`)
- Persona canon: `packages/agent/src/persona-data.ts` (22 personas total; 19 in onboarding picker; 3 meta-personas hidden)
- Onboarding shell: `apps/web/src/components/os/overlays/OnboardingWizard.tsx` (8-step shell with `STEP_NAMES` constant)
- Theme: `apps/web/src/waggle-theme.css` (Hive DS tokens)
- Voice: `docs/BRAND-VOICE.md`
- Architecture: `docs/ARCHITECTURE.md`
## Revision log
- **r1 (2026-05-07 14:09)** — initial draft, wrong direction (assumed flat sidebar). Mockups also generated in wrong direction; discarded.
- **r2 (2026-05-07 14:30)** — corrected per Marko: documented the actual live Mac-OS-style dock + windowed apps + existing TIER_DOCK_CONFIG. Spec now AUDITS existing code instead of redesigning. 5 dock items at Essential matched against `TIER_DOCK_CONFIG.simple` (correct). Memory pulled from Essential to Standard+ (matches code). Added zone-parent + minBillingTier handling. Onboarding gap identified: template+persona steps don't filter by tier.
- **r3 (2026-05-08)** — reframed "Pre-installed skills/tools/connectors at Essential" section per Marko's pushback: capping skills/connectors at Essential reduces capability without simplifying anything (skills are auto-loaded regardless; connectors are zero-installed by default). Replaced with personalize-don't-cap framing: all 18 skills stay loaded, all 148 connectors stay reachable, persona-aware primary recommendation surface drives the connector landing tile. Source of truth: `packages/shared/src/connector-recommendations.ts` (22-persona map + universal fallback, validated against `mcp-catalog.ts` membership in tests). Closed Q2 + Q3 against this approach. Phase 4b will wire ConnectorsApp landing + onboarding "which tools?" step; Phase 4c will add chat skill hints.