moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,338 @@
# 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.