nexus/docs/specs/2026-04-11-nexus-layout-overhaul.md
Nexus Dev 428f033690 refactor(nexus): wave 2.5 follow-ups (presentations + proj derivatives)
Three coordinated changes after reviewing the wave 2 subagent reports:

1. Restore Presentations as the 9th Studio workshop.

Phase 10's subagent dropped Presentations from the workshop grid
because the spec's eight-workshop list didn't include it. But
.planning/PROJECT.md explicitly lists "Presentations & video
generation via Remotion" as an Active v1.7 requirement and the
existing PresentationPanel.tsx is already a real working Remotion
generator. Dropping it was silent feature regression.

  - workshops.ts: add "presentations" slug + Presentation Lucide
    icon, placed between social and convert in canonical order
  - classifyIntent.ts: add pitch-deck / slide-deck / demo-video /
    keynote intent routing (before social so "pitch deck" wins)
  - StudioWorkshopDetail.tsx: import PresentationPanel and add a
    "presentation" case in WorkshopBody
  - workshops.test.ts: expected canonical order updated to 9 slugs
  - classifyIntent.test.ts: 4 new parameterized rows for presentations
  - WorkshopCard.test.tsx: index 7 is now PRESENTATIONS, 8 is CONVERT
  - WorkshopGrid.test.tsx: expected card count 9, canonical order

2. ProjectCard hero-stat derivatives instead of em-dash city.

The shared Project record has none of the fields the spec §7.1 card
depends on: milestoneProgress, nextGate, costBurned, per-project
agent count, phase/milestone array. Wave 2 shipped every card with
"—%" and blank hero numbers — visually underwhelming for a layout
whose whole point is the 72px volt performance stat.

Compute best-effort proxies on the client from data that exists:

  - progress: closed_issues / total_issues × 100, from a single
    issuesApi.list(companyId) query grouped by projectId
  - nextGateName: first pending approval whose payload.projectId
    matches, from a single approvalsApi.list(companyId, "pending")
    query
  - lastActivity: max(project.updatedAt, newest issue.updatedAt in
    the project), rendered as "8m ago"-style diff

Each proxy is annotated with // TODO(phase-11.5) for replacement
when real backend aggregates land. phase, costBurnedCents, and
per-project agent count remain hard gaps — rendered as null which
the card surfaces as em-dashes. These three are explicitly queued
for Phase 11.5.

No backend changes; everything derives from existing endpoints.
Two new useQuery calls in Projects.tsx (issues + pending approvals)
both fire per-company, not per-project, so they stay cheap for the
~dozens-of-projects scale the list targets.

3. Spec updated 8 → 9 workshops everywhere it referred to the count.

docs/specs/2026-04-11-nexus-layout-overhaul.md:
  - §2 IA table: 8 → 9 workshops
  - §6 ASCII header: Eight → Nine
  - §6.3 section title: Eight workshops → Nine workshops
  - §11 decisions log #16: amendment note explaining the 8→9 bump
  - §13 phase 10 description: 8-card → 9-card, with Presentations
    explicitly called out
  - "Folds into Studio as the 8th workshop" → "Folds into Studio
    as a workshop (the legacy /convert route is preserved for
    backwards compat)"

Verification: 75/75 studio tests passing; 52/52 projects tests
passing; tsc clean on studio/ + projects/ + Projects.tsx +
ProjectDetail.tsx + StudioWorkshopDetail.tsx.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 13:04:36 +00:00

55 KiB
Raw Blame History

Nexus Layout & Information Architecture Overhaul

Status: Approved 2026-04-11 — ready for implementation planning Branch: nexus/design-system-migration Companion docs: DESIGN.md (visual language), MIGRATION-PLAN.md (visual migration phases 17 — this spec defines phases 816)


1. Thesis

Nexus is not a SaaS dashboard with a chat panel bolted on. Nexus is a chat with a workshop attached.

The current frame inverts this: a Paperclip-derived corporate dashboard occupies the center, and chat is a 380px slide-in panel on the right that competes with a PropertiesPanel for shared real estate. This is exactly backwards for a single-user, self-hosted personal AI tool whose tagline is "Your personal AI. That also builds things."

In the new frame, the Assistant is the canvas. Everything else — Studio, Projects, Settings — is a destination you visit and return from, not a peer that competes with chat for screen real estate. The Project Builder backend (issues, agents, gates, costs, activity, org) is demoted from global navigation to per-project tabs. You only see it when you've drilled into a specific project. There is no global "Issues" route, no global "Agents" route, no global "Costs" route — those concepts only exist scoped to a project.


2. Information architecture

Primary destinations (in the global icon rail, always visible)

Slot Destination Route Mental model
1 Assistant /assistant The home screen. Voice in, voice out. The chat IS the app.
2 Studio /studio Workshop selector for content generation (9 workshops).
3 Projects /projects List of all projects with health stats.
4 Settings /settings Workspace, Local AI, Cloud, Voice, Skills, Routines, Telegram, About.

Four destinations. Period. No "Dashboard", no "Inbox", no "Recipes" slot, no "add company" button.

Secondary destinations (only inside Project Detail)

When you drill into /projects/:id, you enter Builder mode and a project tab strip appears under the header:

OVERVIEW · ISSUES · AGENTS · GATES · COSTS · ACTIVITY · ORG

These are scoped to one project. They are not addressable globally. Routes: /projects/:id/overview, /projects/:id/issues, etc.

Tertiary surfaces (live inside Settings)

  • Skills — Skill Aggregator browse/install/assign UI
  • Routines — workspace-level cron jobs (currently a top-level route, demoted)
  • Telegram bridge — config, not nav
  • Cloud providers / API keys — config
  • Voice — STT/TTS config

Killed (removed from the app entirely)

What Why
Company switcher / "add company" / "manage companies" / multi-tenant UI Nexus is single-workspace by design
Global Dashboard route as landing page Assistant is the landing page; the dashboard concept becomes the Assistant's conversational greeting
Global Issues / Agents / Approvals / Costs / Activity / Inbox / Org / Goals routes Demoted to per-project tabs (or fold into Overview)
Global Routines route Moved to Settings (cron jobs are workspace config, not a workflow)
ChatPanel.tsx as a slide-in right rail Killed entirely; chat becomes the Assistant route
PropertiesPanel as a standing right-rail fixture Pages that need it render it inline themselves
280px left sidebar with company switcher / sidebar projects / sidebar agents Replaced by 56px icon rail
MobileBottomNav (company-aware) Replaced by 4-icon bottom bar matching the desktop rail
Theme cycle button (Catppuccin/Tokyo/etc.) Binary light/dark only, configured in Settings, no toggle in chrome
ConvertPage as a top-level route Folds into Studio as a workshop (the legacy /convert route is preserved for backwards compat)
InboxRootRedirect, LegacySettingsRedirect, OnboardingRoutePage URL machinery Simpler routing
PluginPage as a top-level route slot Plugin pages render inside Settings or inside a project
Any UI string containing "company", "companies", "tenant", "workspace member" Vocabulary cleanup; replace with "workspace" or remove

3. Visual language (DESIGN.md inheritance)

The overhaul does not introduce a new visual language. It uses DESIGN.md verbatim. Recap of the binding rules for this spec:

  • Canvas: pure black #000000. No surface differentiation between rail/header/canvas — they all bleed into the same black.
  • Sole chromatic accent: Neon Volt #faff69. Used for active states, borders on selected items, hover targets, hero performance numbers, link hover. Never as a fill background outside CTA buttons.
  • Secondary CTA: Forest Green #166534 for "Create project", "New", "Run" buttons.
  • Pressed/active text: Pale Yellow #f4f692.
  • Workhorse border: Charcoal rgba(65,65,65,0.8). The single border color for cards, dividers, inputs.
  • Typography: Inter (variable, weight 400900). Inconsolata for code/numbers. Inter Black 900 for hero performance numbers (project %, milestone count). Uppercase + 1.4px tracking for section labels and breadcrumbs.
  • Radius scale: 4px (sharp), 8px (comfortable), 9999px (pill). Nothing else.
  • Depth: border-based, not shadow-based. Inset shadow Level 4 for "pressed into the surface" active states. Volt border highlight (Level 5) for featured/selected.
  • Mode: dark default. Light mode is an accessibility alternative per MIGRATION-PLAN.md §5; this spec assumes dark mode for all wireframes.

Anything in this spec that conflicts with DESIGN.md, DESIGN.md wins. Update this spec, not DESIGN.md.


4. Global frame

Constant chrome that appears on every page. Two pieces: left icon rail and top strip.

4.1 Left icon rail

┌──┐
│  │  ← 8px top padding
│ ⬢│  ← Nexus mark (volt), 24×24, click → Assistant
│  │
│ ◆│  ← MessageCircle (Lucide) — Assistant
│  │
│ ▲│  ← Sparkles (Lucide) — Studio
│  │
│ ◇│  ← FolderKanban (Lucide) — Projects
│  │
│  │  ← (gap, flex-1)
│  │
│ ⚙│  ← Settings (Lucide) — Settings
│  │  ← 8px bottom padding
└──┘
56px wide, 100vh tall, pure black background, no border

Specs:

  • Width: 56px, locked. No collapse, no expand, no hover-grow.
  • Background: #000000, no border, no shadow.
  • Position: position: fixed; left: 0; top: 0; bottom: 0; — independent of page scroll.
  • Icons: Lucide icons at 20×20. Default state: silver #a0a0a0, stroke 1.5. Hover: volt #faff69. Active (current route): volt + 2px volt vertical bar on the right edge of the rail aligned with the icon. Never a fill background behind the icon — DESIGN.md forbids volt as background.
  • Tooltips: on hover, render a tooltip 12px to the right of the rail with the destination name in uppercase, 11px Inter 600, 1.4px tracking, silver text on near-black #141414 with a 1px charcoal border. Sharp 4px radius. Delay 300ms.
  • Click: navigates immediately. No transitions on the rail itself; the canvas content fades.
  • Nexus mark at top: small geometric logo in volt. Click → /assistant. This is the only volt-filled element in the rail.
  • Settings pinned at bottom: flex layout (flex-direction: column, Settings slot has margin-top: auto).

Accessibility:

  • <nav aria-label="Primary"> with each icon as <a> element.
  • Each link has aria-label matching the tooltip text.
  • aria-current="page" on the active link.
  • Focus ring uses volt at 2px offset.

4.2 Top strip

┌──────────────────────────────────────────────────────────────────┐
│ ASSISTANT                              ⌘K     ◉ MIC              │
└──────────────────────────────────────────────────────────────────┘
   ▲                                       ▲       ▲
   │                                       │       │
   mode label                            search   voice

Specs:

  • Height: 48px. Background: #000000, bottom border: 1px charcoal.
  • Position: position: sticky; top: 0; within the canvas column (not over the rail).
  • Left: mode label / breadcrumb. Inter 600, 14px, uppercase, 1.4px tracking. Silver for non-active segments, volt for the leaf segment (current location). Slash-separated when nested: PROJECTS / NEXUS-DESIGN-MIGRATION. Click any non-leaf segment to navigate up.
  • Right cluster (right-aligned, 16px gap):
    • ⌘K — palette trigger button. Renders the kbd glyph in Inconsolata 12px, charcoal background, pale silver border, 4px radius. Click or Cmd+K opens the global command palette.
    • ◉ MIC — global voice mic button. 32×32 round button (8px radius — not pill, per DESIGN.md "no pill except for toggles"). States:
      • Idle: forest green dot (8×8) centered. No animation.
      • Listening: volt fill, 1.5s pulse loop, expanding volt ring at 60% opacity.
      • Speaking (TTS playback): silver fill, no pulse.
    • Tap-to-talk from any page. See §5.5 for what voice does in each mode.
  • No theme toggle, no notifications icon, no user avatar, no sleep button. Single-user self-hosted; these are all noise.

4.3 The "killed" right rail

The current ChatPanel.tsx (380px slide-in chat) and PropertiesPanel (slide-in property inspector) do not exist as global elements in the new frame. There is no right rail in the chrome. Pages that need contextual side content render it inline within their own layout (e.g., IssueDetail may render an issue-properties column at >1280px; that's a page-level decision, not chrome).


5. Mode 1 — Assistant (/assistant)

The default landing screen and the gravitational center of the app.

5.1 Layout

┌──┬───────────────────────────────────────────────────────────────┐
│  │ ASSISTANT                              ⌘K   ◉ MIC             │
│  │───────────────────────────────────────────────────────────────│
│  │                                                               │
│ ⬢│                                                               │
│  │  TODAY · 10:42                                                │
│ ◆│  ─────────────────                                            │
│  │                                                               │
│ ▲│       ┌──────────────────────────────────────────┐            │
│  │       │ user message bubble (right-aligned)      │            │
│ ◇│       └──────────────────────────────────────────┘            │
│  │                                                               │
│  │  ┌──────────────────────────────────────────────┐             │
│  │  │ assistant message bubble (left-aligned)      │             │
│  │  └──────────────────────────────────────────────┘             │
│  │                                                               │
│ ⚙│  ╭────────────────────────────────────────────────────────╮   │
│  │  │  ░░ ▆▆ ▂▂ ░░ voice waveform                            │   │
│  │  ├────────────────────────────────────────────────────────┤   │
│  │  │  Type a message or hold space to talk…           ↗ ◉   │   │
│  │  ╰────────────────────────────────────────────────────────╯   │
│  │                                                               │
│  │  ⊕ Promote to project    📎 Attach    🧠 Memory   📁 History  │
└──┴───────────────────────────────────────────────────────────────┘

5.2 Components

Component Purpose Implementation note
Conversation thread Full-bleed, no inner scroll columns. Max-width 760px centered in canvas. Messages alternate left/right with 16px gap. Reuses message-rendering primitives from ChatMessageList.tsx but in a new container layout.
Day pip TODAY · 10:42 between message groups. Inter 500, 11px, 1.4px tracking, silver. Render between message clusters when day or hour changes.
Voice waveform Always visible above text input. Idle = flat baseline. Listening = volt bars. Reuses VoiceWaveform.tsx; lift it from inside ChatPanel into the Assistant page.
Text input Below waveform, same surface, hairline divider between. Sharp 8px radius, charcoal border, near-black #141414 fill, generous 24px vertical padding. New component AssistantInputBar.tsx.
Send / mic inline button Right edge of input row. Mirrors the global mic in state. Shared mic state via existing voice context.
Action strip Below input bar. 4 contextual actions in an 8px-gap row. New component. See below.

5.3 The action strip

Action Visibility Behavior
⊕ Promote to project Only when the active conversation is brainstormable (existing brainstormer pattern decides eligibility) Triggers the promote-to-project transition (§5.6). Volt outline button.
📎 Attach Always File picker. Reuses existing upload backend.
🧠 Memory Always Opens memory slide-over from the right (340px wide). Shows what the assistant remembers about you, editable.
📁 History Always Opens conversation list slide-over from the left (320px wide), butted against the icon rail. Lists conversations grouped by today/yesterday/this-week/older.

The 160px conversation-list column inside the current ChatPanel moves to the History slide-over. No persistent column eats horizontal space.

5.4 The conversational home state

When you open Assistant with no active conversation, you do not see an empty thread. You see a status greeting from the assistant itself:

                                                                   
   ┌──────────────────────────────────────────────────────────┐    
   │ Good morning, Mikkel.                                    │    
   │                                                          │    
   │ Since we last talked:                                    │    
   │  • nexus-design-migration: 4 commits, Phase 4 ready      │    
   │  • personal-finance-dashboard: idle 3 days               │    
   │  • 1 gate awaiting approval (nexus, Phase 4 audit)      │    
   │                                                          │    
   │ What do you want to do?                                  │    
   └──────────────────────────────────────────────────────────┘    
                                                                   
   [voice waveform + input bar]                                    

This replaces the global Dashboard. The dashboard is a conversational greeting from your assistant, not a grid of widgets. The data behind it (active agents, pending gates, recent completions, stale projects) comes from the same backend that the old Dashboard route used; the rendering is a single assistant message instead of a layout of cards.

Implementation: the home greeting is a synthesized assistant turn that the server generates on Assistant page load when no active conversation is selected. It's not a real chat message stored in the DB — it's a transient render.

5.5 Voice from anywhere

The mic in the top header is global. Tap it from any mode. Voice goes to the Assistant inbox, queued for next time you open Assistant.

  • In Assistant mode: voice becomes a chat message in the active conversation (existing v1.6 behavior).
  • In Studio / Projects / Settings: voice is captured and held as a pending Assistant message. A small volt indicator dot appears on the Assistant icon in the rail, indicating "you have queued voice waiting." Click Assistant → the queued voice is appended as the next user message and the assistant responds.

We deliberately do not parse voice as UI commands ("close issue 42") in this spec. Single inbox path; simpler; no failure modes around mode-specific intent parsing. If we ever want command-mode voice, that's a separate feature behind an explicit toggle.

5.6 The promote-to-project transition

The most important visual moment in the app. This is when a chat becomes a project.

Trigger: user clicks ⊕ Promote to project in the action strip.

Animation sequence (700ms total):

  1. 0200ms: the conversation thread compresses from 100% canvas height to a 30% ribbon at the top. Easing: cubic-bezier(0.22, 1, 0.36, 1). Inset shadow Level 4 (DESIGN.md "pressed") fades in along the bottom edge of the compressed thread.
  2. 200500ms: the brainstormer panel rises from the bottom of the canvas, occupying the bottom 70%. It contains the brainstormer flow: goal, acceptance criteria, gates, agent assignments (PM auto-assigned, Engineer template selected from skill aggregator).
  3. 500700ms: a small SOURCE CONVERSATION label fades in above the compressed thread.
        BEFORE                                  AFTER (animation complete)
┌──────────────────────────┐         ┌──────────────────────────┐
│ ASSISTANT                │         │ ASSISTANT                │
│──────────────────────────│         │──────────────────────────│
│                          │         │ SOURCE CONVERSATION      │
│  full chat thread        │         │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │
│                          │         │ ▓ chat thread (30% ht)  │
│                          │   ───►  │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │
│                          │         │──────────────────────────│
│                          │         │  BRAINSTORMER            │
│  ┌─────────────────────┐ │         │  ──────────              │
│  │ input + ⊕ promote   │ │         │  Goal: ____________      │
│  └─────────────────────┘ │         │  Acceptance: _________   │
│                          │         │  [ Create project ]      │
└──────────────────────────┘         └──────────────────────────┘

On Create project:

  • A new project row is created (existing project create endpoint).
  • The brainstormer panel collapses.
  • The compressed chat thread restores to full height.
  • A small permanent banner at the top of the chat reads → Project: NEXUS-DESIGN-MIGRATION (link to project detail).
  • The user is not auto-navigated to the project. They stay in Assistant. The project appears in the Projects list and is also linked from the chat itself.

5.7 Origin chat preservation

The chat that births a project is preserved as a living conversation, not frozen as a spec snapshot. Decisions:

  • The chat stays editable and continuable after promotion.
  • The chat is permanently linked to the project (small banner at the top of the chat: → Project: PROJECT-NAME).
  • The project's OVERVIEW tab has an ORIGIN CHAT card linking back to the conversation.
  • New messages added to the chat after promotion do not automatically modify the project. The chat is the assistant's relationship; the project is the implementation contract.
  • If the user wants to update the project from a later chat message, they explicitly use a → Update project action (out of scope for this spec; a future affordance).

6. Mode 2 — Studio (/studio)

Workshop selector for content generation. Replaces the current 7-tab ContentStudio.tsx and folds in ConvertPage.

6.1 Layout

┌──┬───────────────────────────────────────────────────────────────┐
│  │ STUDIO                                  ⌘K   ◉ MIC            │
│  │───────────────────────────────────────────────────────────────│
│  │                                                               │
│ ⬢│   STUDIO                                                      │
│  │   ─ ─ ─ ─ ─                                                   │
│ ◆│   Nine workshops. Pick one or describe what you need.         │
│  │                                                               │
│ ▲│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐           │
│  │  │ DIAGRAMS     │ │ ICONS        │ │ THEMES       │           │
│ ◇│  │ Mermaid →    │ │ SVG sets     │ │ Color → full │           │
│  │  │ rendered     │ │              │ │ palette      │           │
│  │  └──────────────┘ └──────────────┘ └──────────────┘           │
│  │                                                               │
│  │  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐           │
│ ⚙│  │ WALLPAPERS   │ │ DOCUMENTS    │ │ BRAND KITS   │           │
│  │  └──────────────┘ └──────────────┘ └──────────────┘           │
│  │                                                               │
│  │  ┌──────────────┐ ┌──────────────┐                            │
│  │  │ SOCIAL       │ │ CONVERT      │                            │
│  │  └──────────────┘ └──────────────┘                            │
│  │                                                               │
│  │  ─────────                                                    │
│  │  Or just describe it: "I need a 1920×1080 wallpaper of …"   ↗ │
└──┴───────────────────────────────────────────────────────────────┘

6.2 Workshop card spec

  • Layout: 3-column grid on >= 1024px, 2-column on >= 640px, 1-column below.
  • Card: 1px charcoal border, 8px radius, transparent fill (canvas black shows through), 24px padding.
  • Hover: background fades to near-black #141414 over 120ms, border stays charcoal, no transform.
  • Title: Inter 700, 24px, uppercase. Pure white.
  • Subtitle: Inter 400, 14px, silver, single line.
  • Icon glyph: Lucide icon at 32×32 in volt, top-right of card.
  • Click: navigates to /studio/{workshop-slug}.

6.3 Nine workshops

Slug Title Source Notes
diagrams DIAGRAMS Existing diagram-renderer Mermaid → rendered SVG/PNG
icons ICONS Existing icon generator SVG from description
themes THEMES Existing theme generator Color → full theme with WCAG AA, exports
wallpapers WALLPAPERS Existing wallpaper-renderer Desktop, mobile, social banners
documents DOCUMENTS Existing pdf-renderer PDF reports, invoices, one-pagers
brand-kits BRAND KITS Existing brand-renderer Full brand identity
social SOCIAL Existing social generator Platform-ready posts, carousels
convert CONVERT ConvertPage.tsx File format conversion (folded in from /convert)

Recipes (v1.8) is not a workshop. Recipes are intelligence embedded into Assistant suggestions, not a separate generation surface (see §10.2).

6.4 Workshop detail view

Each workshop, when opened, takes the user into a focused workspace:

  • Mode label: STUDIO / DIAGRAMS
  • Layout: two-column on desktop. Left column = parameters/prompt input. Right column = live preview.
  • Action bar: bottom of right column. [Save] [Export] [Send to Assistant].
  • The "Send to Assistant" action queues the generated artifact as an attachment for the next Assistant message — closes the loop between Studio and Assistant.

6.5 Studio freeform prompt

Bottom of the workshop selector page: a freeform text input that routes to the right workshop based on intent ("I need a 1920×1080 wallpaper of …" → opens Wallpapers workshop with that prompt pre-filled). The routing is a small classifier that maps intent to workshop slug. If routing fails, the prompt becomes an Assistant message.


7. Mode 3 — Projects + Builder mode

7.1 Projects list (/projects)

┌──┬───────────────────────────────────────────────────────────────┐
│  │ PROJECTS                                ⌘K   ◉ MIC            │
│  │───────────────────────────────────────────────────────────────│
│  │                                                               │
│ ⬢│   PROJECTS                            ⊕ NEW PROJECT (forest)  │
│  │   ─ ─ ─ ─ ─                                                   │
│ ◆│                                                               │
│  │  ┌─────────────────────────────────────────────────────────┐  │
│ ▲│  │ NEXUS-DESIGN-MIGRATION              ●  4 agents active   │  │
│  │  │ ────────────────────────────                            │  │
│ ◇│  │  47%        Phase 3 of 7  ·  Next gate: Phase 4 audit   │  │
│  │  │  ▓▓▓▓▓░░░░░                                              │  │
│  │  │  $14.20 burned · last activity 8m ago                    │  │
│ ⚙│  └─────────────────────────────────────────────────────────┘  │
│  │                                                               │
│  │  ┌─────────────────────────────────────────────────────────┐  │
│  │  │ PERSONAL-FINANCE-DASHBOARD         ◉  idle              │  │
│  │  │ ...                                                      │  │
│  │  └─────────────────────────────────────────────────────────┘  │
└──┴───────────────────────────────────────────────────────────────┘

Project card:

  • Layout: full-width on < 1024px, 2-up on >= 1024px. Stack vertically with 16px gap.
  • Card: 1px charcoal border, 8px radius, transparent fill.
  • Title row: project slug (uppercase) in Inter 700 16px white. Status dot on the right (forest = idle, volt pulse = working, pale yellow = waiting on gate).
  • Hero stat: percentage in Inter Black 900, 72px, volt. This is the "performance stat" from DESIGN.md §4 — the visual proof that something is happening. Format: 47% with no extra label.
  • Sub-line: Phase 3 of 7 · Next gate: Phase 4 audit — Inter 500, 14px, silver.
  • Progress bar: 8px tall, charcoal track, volt fill. Sharp 4px corners, no pill.
  • Footer line: $14.20 burned · last activity 8m ago — Inter 400, 12px, silver.
  • Click: navigates to /projects/{slug}/overview.

No table view, no filters, no sort dropdowns. Search and filter live in ⌘K (active projects, projects with pending gates, etc.).

New project button: top-right corner, Forest Green per DESIGN.md secondary CTA. Click → opens an empty brainstormer panel inline (same component as the promote-to-project transition, but starting from a blank thread).

Empty state: if no projects exist, the canvas shows a single full-bleed message — NO PROJECTS YET in Inter Black 900 96px volt, with a ⊕ START YOUR FIRST PROJECT Forest Green CTA below.

7.2 Project Detail (/projects/:slug/...) — Builder mode

The header changes when you enter a project:

  • Mode label becomes PROJECTS / PROJECT-NAME (slash-separated breadcrumb, last segment in volt)
  • Project tab strip appears directly under the header, height 40px, charcoal bottom border:
OVERVIEW · ISSUES · AGENTS · GATES · COSTS · ACTIVITY · ORG
─────────
  • Tabs: uppercase, 1.4px tracking, Inter 600 14px, silver default. Active tab: volt text + 2px volt underline. Hover: text shifts to volt.
  • 24px gap between tabs, 24px left padding to align with mode label.
  • The tab strip is sticky below the header strip (position: sticky; top: 48px;).

7.2.1 OVERVIEW (default tab)

NEXUS-DESIGN-MIGRATION
─ ─ ─ ─ ─

47%                              4 AGENTS ACTIVE
───                              ────────────────
72px Inter Black volt            Inter 700 14px silver

┌──────────────────────────────────────────────────────┐
│ Current milestone: Phase 4 — typography & radius      │
│ ─────────────────                                     │
│ • [✓] DESIGN.md drafted                               │
│ • [✓] MIGRATION-PLAN.md approved                      │
│ • [✓] Phase 1 — foundation                            │
│ • [✓] Phase 2 — status colors                         │
│ • [✓] Phase 3 — raw utility sweep                     │
│ • [○] Phase 4 — typography + radius   ← NEXT GATE     │
│ • [ ] Phase 5 — theme preview rewrite                 │
│ • [ ] Phase 6 — hljs                                  │
│ • [ ] Phase 7 — visual QA                             │
└──────────────────────────────────────────────────────┘

┌──────────────────┐  ┌──────────────────┐
│ ORIGIN CHAT      │  │ ACTIVITY (LAST 24H) │
│ "Don't just      │  │ • 14 commits         │
│  redesign the    │  │ • 3 issues closed    │
│  right rail …"   │  │ • 1 gate awaiting    │
│ → Open chat      │  │ • $4.60 burned       │
└──────────────────┘  └──────────────────┘
  • Hero stat row: percentage at 72px Inter Black volt + agents-active counter at 14px silver. Two columns. The percent is the visual focal point of the page.
  • Milestone checklist card: the project's milestones as a checklist. Charcoal border, 8px radius, 24px padding. Title in Inter 700 16px uppercase. Items in Inter 500 14px white (completed) or silver (pending). The next gate marker uses pale yellow #f4f692 for the bullet and a ← NEXT GATE label.
  • Origin chat card: small card that links back to the conversation that birthed this project. First line of the conversation is rendered as a quote.
  • Activity card: rolling 24h activity feed. Reuses the global Activity page data, scoped to this project.

7.2.2 ISSUES tab

Project-scoped issue list. Reuses the existing IssuesList component but dropping the company filter (single workspace) and scoping by project ID. No global "Issues" route.

7.2.3 AGENTS tab

Project-scoped agent list. Shows agents assigned to this project, their roles (PM, Engineer, Generalist), status (idle/working/blocked), and current task. Reuses existing agent components but scoped.

7.2.4 GATES tab

Renamed from "Approvals" to "Gates" because it matches the brainstormer/pipeline mental model (each project has gates that the user approves to advance). Shows all pending and historical gate approvals for this project.

7.2.5 COSTS tab

Project-scoped cost burn. Agent-by-agent breakdown. Reuses cost-tracking backend.

7.2.6 ACTIVITY tab

Full activity feed for this project. The 24h preview on Overview is a slice of this.

7.2.7 ORG tab

Project-specific org chart (which agents report to which, who handles what). Shown as a tab only for projects with multi-agent orchestration; hidden for single-agent projects.

7.3 What's NOT in Builder mode

Removed surface Where it goes
Routines Settings → Routines section
Goals Folded into the milestone checklist on Overview
Inbox ⌘K + the global Assistant icon dot indicator
Approvals (as global) Becomes per-project Gates tab
Dashboard Becomes Assistant conversational greeting

8. Mode 4 — Settings (/settings)

8.1 Layout

Single-column scroll, no nested settings sub-routes. The current Paperclip nested settings tree (/instance/settings/general, /instance/settings/integrations, etc.) collapses into one scrollable page with cards.

SETTINGS
─ ─ ─ ─ ─

┌──────────────────────────────────────────────────────┐
│ WORKSPACE                                            │
│ ─────────                                            │
│ Root directory       /home/mikkel/nexus      [edit]  │
│ Theme                ● dark   ○ light                │
│ Re-run onboarding    [open wizard]                   │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ LOCAL AI                                             │
│ ─────────                                            │
│ Hermes provider      qwen-coder:32b  (28GB VRAM)    │
│ Whisper STT          base.en (140MB) ▼              │
│ Piper TTS voice      en_US-hfc_female-medium ▼      │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ CLOUD PROVIDERS                                      │
│ ────────────────                                     │
│ Anthropic API key    ●●●●●●●●●●  (set)              │
│ OpenAI API key       (not set)                       │
│ Puter.js             (zero-config, enabled)          │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ SKILLS                                               │
│ ──────                                               │
│ [browse] [installed: 12]  [groups: 4]                │
│ ...skill aggregator UI...                            │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ ROUTINES                                             │
│ ────────                                             │
│ Daily summary      every 09:00  [edit] [pause]       │
│ Cost report        every Mon 08:00                   │
│ + add routine                                         │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ TELEGRAM BRIDGE                                      │
│ ────────────────                                     │
│ Bot token            ●●●●●●●●●●                      │
│ Allowed chat IDs     [list]                          │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ ABOUT                                                │
│ ──────                                               │
│ Nexus 1.7-dev · Paperclip fork · MIT                 │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ DANGER ZONE                                          │
│ ────────────                                         │
│ [Reset workspace] [Delete all conversations]         │
└──────────────────────────────────────────────────────┘

8.2 Section card spec

  • 1px charcoal border, 8px radius, transparent fill.
  • 24px padding.
  • Title: uppercase Inter 600 14px, 1.4px tracking, silver. Followed by a hairline rule.
  • Content: rows of label / value / action triples.
  • Section gap: 24px between cards.

8.3 Skills section

The Skill Aggregator (browse, install, assign per-agent) lives inside the SKILLS card. Same component, just rendered as a Settings section instead of a top-level page. Browse opens an inline drawer; assignments per-agent are configured here.

8.4 Routines section

Cron jobs that the workspace runs. Currently a top-level Routines route — demoted here. The current RoutineDetail page becomes a slide-over from the Routines section card.


9. Mobile

┌──────────────────────┐    ┌──────────────────────┐
│ ASSISTANT      ◉ ⌘K  │    │ STUDIO        ◉ ⌘K   │
│──────────────────────│    │──────────────────────│
│                      │    │ ┌──────┐ ┌──────┐    │
│  chat thread         │    │ │ DIAG │ │ ICON │    │
│  full bleed          │    │ └──────┘ └──────┘    │
│                      │    │ ┌──────┐ ┌──────┐    │
│                      │    │ │ THEME│ │ WALL │    │
│ ┌──────────────────┐ │    │ └──────┘ └──────┘    │
│ │ ▒▒▒▒▒ waveform   │ │    │ ┌──────┐ ┌──────┐    │
│ │ ──────────────── │ │    │ │ DOC  │ │ BRAND│    │
│ │ Type or hold ◉  │ │    │ └──────┘ └──────┘    │
│ └──────────────────┘ │    │ ┌──────┐ ┌──────┐    │
│                      │    │ │ SOC  │ │ CONV │    │
│──────────────────────│    │──────────────────────│
│  ◆     ▲     ◇    ⚙ │    │  ◆     ▲     ◇    ⚙ │
└──────────────────────┘    └──────────────────────┘

9.1 Mobile changes from desktop

  • Bottom tab bar replaces the left icon rail. Same 4 destinations (MessageCircle, Sparkles, FolderKanban, Settings). 56px tall, charcoal top border. Active tab: volt icon + volt bar above the icon.
  • Top header strip stays. Loses ⌘K text (still tappable as an icon). Mic stays.
  • Assistant on mobile is full-bleed. Reuses existing MobileChatView.tsx pattern as the foundation.
  • Project sub-tabs become a horizontally-scrolling strip under the header. No shrinking, no wrapping.
  • Studio grid drops to 2 columns on mobile.
  • Promote-to-project transition on mobile uses a full-screen takeover instead of the split layout — the brainstormer slides up and covers the chat completely.
  • History slide-over on mobile uses a full-screen sheet instead of a left drawer.
  • Memory slide-over same.

9.2 Mobile breakpoint

Single breakpoint: >= 768px is desktop frame, < 768px is mobile frame. Matches the existing useMediaQuery("(min-width: 768px)") in the codebase.


10. Cross-cutting features

10.1 ⌘K command palette

Single global search and command surface. Opens with Cmd+K / Ctrl+K or by clicking the ⌘K button in the top strip.

Searches:

  • Conversations (by title or recent message text)
  • Projects (by name, status filter, gate filter)
  • Issues (by title, by project)
  • Agents (by name, by role)
  • Recipes (by name, by tag)
  • Settings (by section name)
  • Studio workshops (by name)

Commands (no search):

  • New project → opens brainstormer
  • New conversation → starts a fresh Assistant thread
  • Open Settings
  • Re-run onboarding
  • Recent recipes (Run "Generate weekly report")

Layout: centered modal, 600px wide, charcoal border, near-black fill, 8px radius. Search field at top in Inconsolata 16px. Results below in scrollable list with category headers in uppercase 11px silver. Selected result has a 2px volt left border and pale-yellow text. Keyboard nav: arrow keys + enter.

10.2 Recipes (v1.8) — embedded in Assistant

Recipes are not a destination. They are intelligence the Assistant uses to make suggestions in chat:

Assistant: "I notice you've done this kind of project before — want me to run the frontend-design + tdd + ship recipe? It took 3 hours and $4.20 last time."

[ Yes, run it ] [ Customize ] [ No, do it from scratch ]

When the user accepts, the recipe executes and the Assistant narrates progress in chat. Recipes are also browsable from ⌘K (recipes: prefix) but there is no recipe browser as a destination.

This means the icon rail has 4 slots, not 5. The reserved circle slot from the proposal is removed.

10.3 Voice as a global affordance

See §5.5. Voice is captured from any mode and queued in the Assistant inbox. Visual indicator: when there is queued voice waiting to be processed, a small volt dot appears next to the Assistant icon in the rail.

10.4 Notifications

There is no global notifications icon. The single notification surface is the volt dot on the Assistant icon when:

  • Queued voice is waiting
  • A pending gate needs approval
  • A long-running agent task has completed

Click Assistant → the assistant tells you what's new in chat. No dropdown, no inbox panel. The Assistant's job is to tell you what changed.


11. Decisions log

Captured from the brainstorming conversation 2026-04-11. These are binding choices the spec is built on.

# Decision Resolved
1 "Chat with a workshop attached" thesis Approved as the product framing
2 Demote Paperclip pages (Issues/Agents/Routines/Goals/Approvals/Costs/Activity/Inbox/Org) from global routes to per-project tabs Approved
3 Single workspace, no company switcher Approved
4 Assistant is the default landing route Approved
5 56px left icon rail with 4 primary destinations Approved
6 Voice mic in top header is global, always visible Approved
7 ⌘K is the universal search; no separate search fields Approved
8 Origin chat is editable and continuable after promotion (not frozen) Approved
9 Recipes are embedded in Assistant suggestions, not a destination. Icon rail has 4 slots, not 5. Approved
10 Assistant home state (no active conversation) is a conversational greeting summarizing project status — replaces the Dashboard Approved
11 Voice in non-Assistant modes queues to Assistant inbox; no per-mode command parsing Approved
12 Icon rail uses Lucide icons (MessageCircle, Sparkles, FolderKanban, Settings) in silver outline + volt active. No abstract geometry. Approved
13 No sleep / lock button Approved (kill it)
14 Skill Aggregator lives in Settings → Skills section Approved
15 Promote-to-project transition: chat compresses to 30%, brainstormer rises into bottom 70%, inset shadow ripple Approved — "ship that exact animation"
16 Studio is a workshop grid (9 cards), not tabs Approved 2026-04-11; amended post-Wave-2 from 8 to 9 to restore Presentations (Active v1.7 req), see §6.3
17 Convert folds into Studio as a workshop, no separate route Approved
18 Project list cards use 72px Inter Black volt percentage as hero stat (DESIGN.md "performance stat" pattern) Approved
19 ChatPanel as a global slide-in right rail is killed entirely Approved
20 PropertiesPanel as a standing global fixture is killed Approved
21 Single notification surface = volt dot on Assistant icon Approved
22 Approvals → Gates rename (matches brainstormer/pipeline mental model) Approved
23 Routines move to Settings → Routines section Approved
24 Goals fold into milestone checklist on project Overview Approved
25 Single mobile breakpoint at 768px; mobile uses bottom tab bar Approved

12. Out of scope (for this spec)

These are explicit non-decisions — we are not designing them in this overhaul, and any future work on them is a separate spec:

  • Light mode visual treatment beyond what MIGRATION-PLAN.md §5 already specifies. Light mode is an accessibility alternative. The wireframes here assume dark mode.
  • Per-project branding overrides. The existing worktree-branding.ts system is untouched.
  • Plugin marketplace UI. Plugins still install via CLI; in-app browse is future work.
  • Voice command parsing in non-Assistant modes (Star Trek mode). Single inbox path only.
  • Update-project-from-chat affordance. The chat is a relationship; the project is a contract; we don't sync the two except at promotion time.
  • Multi-window / tear-off panels. Single window only.
  • Multi-select / batch operations on projects or issues. Single-target only.
  • Custom user themes. Binary light/dark only.
  • High-contrast accessibility mode beyond WCAG AA. Not in scope.

13. Implementation phases (extends MIGRATION-PLAN.md to phases 816)

The visual migration plan ends at Phase 7 (visual QA of the ClickHouse repaint). This spec defines structural phases 816, executed in sequence after Phase 7 completes (or in parallel if a worktree is used).

Implementation directive (binding): Each phase below is implemented by dispatching subagents in parallel wherever phases or sub-tasks share no files. The user has explicitly requested subagent-driven development for this overhaul because of its size. Sequential implementation is wrong for this work. See MIGRATION-PLAN.md §11 (added in this revision) for the dispatch pattern.

Phase Title Scope Independence
8 Frame skeleton New 56px icon rail, 48px top strip, killed sidebar/ChatPanel/PropertiesPanel as global elements. Routing simplified (no company prefix as a layout requirement). Old pages render in new frame but look weird — that's expected. Foundational; blocks phases 915
9 Assistant mode Move PersonalAssistant.tsx to be the canonical Assistant route. Implement History (left) and Memory (right) slide-overs. Implement conversational home state for empty-conversation mode. Replace inline conversation column with slide-over. Parallelizable with 10, 11
10 Studio mode Refactor ContentStudio.tsx from tabbed layout to a 9-card workshop grid. Fold ConvertPage in as a workshop. Keep the existing Presentations (Remotion) panel as a workshop. Add freeform Studio prompt with intent routing. Build workshop detail two-column layout. Parallelizable with 9, 11
11 Projects + Builder mode Build new Projects list with hero-stat cards. Build Project Detail layout with 7-tab Builder strip. Demote global Issues/Agents/Approvals/Costs/Activity/Org/Goals/Inbox routes to per-project tabs. Rename Approvals → Gates. Reuse existing list components, scope by project ID. Parallelizable with 9, 10
12 Promote-to-project transition The 700ms animation: chat compresses to 30%, brainstormer rises into 70%, inset shadow ripple, source-conversation label, post-creation banner linking chat to project. Origin chat preservation logic. Depends on 9 (Assistant) and 11 (Projects)
13 Settings consolidation Single-column Settings with all sections. Skills section (Skill Aggregator inline). Routines section (demoted from top-level). Re-run onboarding link. Drop nested settings routes. Parallelizable with 12, 14, 15
14 Voice + ⌘K globalization Mic in top header with three states (idle/listening/speaking). Voice queues to Assistant inbox from any mode with volt-dot indicator on Assistant icon. ⌘K palette searches conversations, projects, issues, agents, recipes, settings, workshops. Replace any in-page search fields. Parallelizable with 12, 13, 15
15 Mobile parity Bottom tab bar matching the desktop rail. Project sub-tabs as horizontal scroll strip. Mobile takeover for promote-to-project. Mobile sheets for History/Memory slide-overs. Parallelizable with 12, 13, 14
16 Cleanup pass (a) Vocabulary sweep — remove "company" from all UI text, replace with "workspace" or remove. (b) Removal pass — delete dead code (old Layout sidebar, old ChatPanel global rail, old MobileBottomNav, theme cycle button code, dead route redirects, dead global pages). (c) Visual QA pass for the new frame. Sequential at the end

Estimated wave structure for parallel dispatch:

Wave 1: [ Phase 8 ]                            # foundational, alone
Wave 2: [ Phase 9 ] [ Phase 10 ] [ Phase 11 ]  # parallel — disjoint files
Wave 3: [ Phase 12 ] [ Phase 13 ] [ Phase 14 ] [ Phase 15 ]  # parallel
Wave 4: [ Phase 16 ]                           # sequential cleanup, alone

Each phase produces an independently committable, atomically reviewable change. The implementation plan (separate doc, written next via the writing-plans skill) will detail file-by-file changes per phase.


14. Open items deferred to implementation planning

These do not need to be answered to start writing the implementation plan, but they will need answers before the corresponding phase ships:

  1. Animation primitives: the promote-to-project transition uses 700ms cubic-bezier easing. The codebase currently uses CSS transitions for everything. Decide whether to introduce Motion (motion/react) for this single complex sequence or hand-roll with CSS keyframes. Recommendation: hand-roll. One-off animation does not justify a new dependency.

  2. Workshop intent classifier: the Studio freeform prompt routes to the right workshop. Decide whether classification runs server-side (LLM call) or client-side (regex/keyword matching). Recommendation: client-side regex first, LLM fallback only if regex fails.

  3. Conversational home state freshness: the Assistant greeting on home-state load reads from project status. Decide cache TTL (refresh on every Assistant page open vs. cached for N minutes). Recommendation: refresh on every open, no cache. The data is small.

  4. ⌘K result ranking: when search returns a mix of conversations, projects, issues, etc., decide the ranking heuristic. Recommendation: recency-weighted, with current-project items boosted if user is currently in a project.

  5. Project tab strip overflow on narrow desktop: if 7 tabs don't fit at narrow desktop widths, decide whether to wrap, scroll, or collapse to a more ▼ menu. Recommendation: horizontal scroll with edge fade, matching mobile.


15. Approval

Approved by Mikkel 2026-04-11 in conversation. Locked-in items: §1 (thesis), §2 (IA), §4 (frame), §5§8 (modes), §9 (mobile), §10 (cross-cutting), §11 (decisions log), §13 (phase plan).

Next step: invoke the writing-plans skill to generate a per-phase implementation plan derived from this spec.