relay-ui-overhaul · epic #475 / RCTX-499

App v3.5 prototypes

Interactive, responsive prototypes for the Relay app overhaul, built on the shipped v3.5-a neutral-first system (tokens.css, verbatim). One universal collapsible rail and a principal top-bar search (⌘K command palette) span every screen. Staged here to riff and confirm before the screens land in relay-app.

App shell — as shipped

Screens confirmed onto the real nav (shell.html's canonical rail groups) and built on the identical shell anatomy — rail, ⌘K top-bar search, list-shell facets. Land in relay-app in tandem.

Manifest — one ground truth explainer · RCTX-409/410

How the Root Manifest is set up and incorporated across the app: the per-user entry vertex projected into many lenses (agent boot, the Overview home, the Graph Map) from one engine. Cross-page breakdown, the shape-encoded node vocabulary (type = shape, never colour), and the recurring “live projection” callout.

Overview — home manifest · RCTX-409/410

The app home renders the owner projection of the Root Manifest — the same map the agent gets at boot and the Graph Map draws (one ground truth, three lenses). A quiet setup nudge (dismissible, one line) points at the dedicated welcome.html screen instead of hosting the full onboarding card inline. Counts strip, unclaimed callout, Streams with attention-share health meters, Series, open Sessions, and Recent relays with read-only provenance (created / claimed / forwarded · sender · via_code when present). The topbar bell is now a working inbox popover with quick notification options (email digest / push alerts). Pointers only, never bodies. Nodes drawn in the gc-* kit vocabulary (RCTX-396) so they swap to the real components with no drift. Fail-open: ?state=empty · ?state=loading.

Overview — as a module host concept · 2026-09-12

The five shipped bands become modules the user arranges, on the identical shell: Customize (drag, ↑↓, width, remove), a catalogue sheet grouped by the screen that lends each module, Needs you pinned and vanishing when cleared, the lens stated once (all my contexts · this hat only), org modules joining with the workspace chip, the activity graph at three widths, and Step 6 · Arrange your dashboard on first run. Kit shared with the profile via ui/activity-modules.{css,js}; the argument is /concepts/activity-modules-v1.html. Proposal, not canon.

Profile — the activity graph, owner and public concept · 2026-09-12

The shipped settings form becomes the edit state; the profile becomes the identity card, a year of contributions one cell a day (year picker, table twin), the owner's modules and Shows on your public profile. View as You · A connection · Public previews exactly what the host computes — a lens that never grants: tier-none modules disappear, counts modules drop to numbers, private contributions join the public count only if opted in, and only as numbers. /u/erik leads with Relay to @erik; private stays the shipped locked state. First run carries Step 6 · What your profile shows with the first cell lit.

Welcome — onboarding own screen · RCTX-409

Getting started, split off Overview onto its own route: a welcome header, a three-step "how Relay works" explainer, and the full-emphasis multi-step setup card (verify email → connect an agent → receive the welcome Code → send your first relay → invite a teammate). Reached from the Overview .setup-nudge or the bell's "Finish setting up" notice, never gating — a plain Skip for now returns to Overview. Same shell, no active rail item (not a permanent destination). The compact tertiary version still lives on Profile → Setup.

Component Canon reference

The design system at a glance, rendered with the shipped CSS — tokens & accent roles, type registers, buttons (ink-flip), badges/chips/status dots, the Code artifact, cards, editorial head, the tool help card (.fi-panel), timeline, empty states — plus the quiet easter eggs (code scramble, signal ripple, console greeting). Light/dark.

Graph Primitives — gc-* kit explorer reference · RCTX-396

The Graph's object vocabulary, interactive: the settled shape alphabet (type = shape, never colour), live type-filter chips wired to the honest counter, .gc-li ranked-twin rows with selection, Code chips (copy + scramble egg), the edge dash grammar, and a playground that composes a row and shows the exact shipped markup. Rendered with the verbatim graph/graph.css.

App Shell as shipped · #482

The universal collapsible rail (56 ↔ 220, brand-mark toggle, hover labels, tier hairlines), workspace switcher, top bar with ⌘K + a now-working bell popover (unread inbox + email/push notification-option toggles) — mirroring the live nav structure, with the slated IA changes annotated (#606 org-connections, #456 status fold, #609 account hub) plus a note on onboarding's move to its own screen.

Screen Reality Matrix audit · 2026-07-18

Every screen in the live app with its v3.5 conformance state — shipped / partial / legacy — source module, and the issue that moves it. The honest per-screen burn-down for epic #475/#449.

Transfers list shell · #451

The shared list-shell anatomy — direction pills · status/state filters · saved views · active-filter chips · count · sort · density (cards / compact / table) · pager — over 120 rows. Search is the top-bar ⌘K palette, not a per-screen box. Outgoing/Incoming vocabulary, honest time, Code copy + scramble, received-tint cards. Full light/dark + mobile — one universal collapsible rail (56px icon rail, tap to expand as an overlay) and a filter sheet; no bottom tab bar.

Series list shell · #452

Named sequences of context, one thread per series. Status pills (All / Active / Archived), Starred / Mine / Has-updates, participant avatars, relay counts, latest Code, and the same density toggle. Table view has click-to-sort columns (Name / Relays / Status / Scope / Updated).

Sessions list shell · #453

AI agent sessions with the distinctive bits: Open / Closed status, handoff chains (continues / handed off / chained), the agent model, Stream linkage, and workspace. Filter by Handoffs; sort the table by Session / Status / Agent / Relays / Updated.

Stream list shell · #454

Stream's own toolbar — search bar, sort dropdown (Last activity / Stalest first / Most items / Recently read / Title A→Z / Created), and the combinable status/type/tag filter-chip row — is the brief's confirmed "most complete, natural donor pattern" and is kept as-is, not redesigned into Transfers' popover facets. The one real gap: Stream renders its entire filtered list with no pager. Adds Transfers' pager component (range · ‹ page numbers › · page size 25/50/100) below the list, plus the personal focus-area hero card, unread pills, staleness-coded age, and a weight bar per card. The has-content guard for the "Meet Stream" intro is already shipped (feature-intro.ts / stream.ts, #455/#604) — not re-touched here.

Send form · #457

The Send form's own progressive disclosure — essentials (title, content, recipient, visibility, max receives) plus the already-shipped "More options" disclosure (tags, expiry, bring-back, series) — is already shipped (send-claim.ts's send-more-options + updateSendMoreOptionsCount()) and reproduced here as-is, not redesigned. The real, confirmed gap was the empty right half of the viewport: adds a live recipient-side preview that updates on every keystroke — the claim-landing card a recipient would actually see (title, sender identity, content preview, visibility badge, tags, receives-left/unlimited, expiry), modeled on doClaimPreview()'s real fields.

Settings sectioned restructure · #459

The unsectioned ~10-card scroll (Plan, Agreements, Profile, Communications, Privacy & Defaults, Session Relays, Slack, Notifications, Loop, Danger Zone) gets a sticky anchor rail — Account / Notifications / Integrations / Program / Danger — with scroll-spy, chosen over tabs so nothing (a skeleton, an error state) ever hides behind an unselected panel. EC-confirmed scope (2026-07-18 issue comment), not a fresh interpretation: change-password UI is omitted entirely (Relay is OTP-only — already gone from the real settings.ts/index.html too, confirmed by re-reading them), the timezone picker defaults to the browser-detected zone instead of first-alphabetical (also already fixed in datetime.ts — this prototype mirrors the real fix rather than re-deriving it), and Export moves out of Danger Zone into its own non-destructive "Data" card near Privacy. Demo strip toggles every async card (Plan/Loop/Slack/Notifications/Communications/Agreements/Autojoin) through loading-skeleton and failure states.

Catalog object browser · #458

Tags (stub) and the shipped server-side Labels (stub — already live, 2026-07-18) sit alongside the new Objects tab (default/active here): a real cross-type table over the whole relay object base — relays, series, sessions, streams in one place. Type facet with counts, a text/tag filter, click-to-sort columns (Name/Title, Type, Status, Updated), a count line, and the Transfers pager component reused near-verbatim. Row click opens a peek drawer with per-type fields and a real "Open in Transfers / Series / Sessions / Stream →" link — every in-scope object type already has a live destination today, so none of the four needed a "#488 coming soon" stub. Table is written so a future deleted-only variant (Trash, #607) or search drill-down (#456) doesn't require a rewrite.

Graph map · #511

The object map — Streams, Series, Sessions, Relays, Resources and the edges between them — as a live screen in the shell (the same projection the Manifest and Overview draw, higher N). Map / List, type filters, an arrange lens (Force / Time / Orbit / Heat / Owner), time window, and honest counts. Focus mode tucks the rail, top bar, and header for a full-frame canvas, with the controls behind a window-shade pull-tab (F / Esc, top-edge hover on desktop, tap on touch). Saved views recall / save / rename filter+lens+window presets in the shared .view chip idiom.

Billing account · RCTX-992

The member-facing half of the billing lifecycle, on the shipped rail (Billing sits under Account). Plan and seats, usage against the plan contract, invoices and receipts, payment method. Its core is the three states the platform actually resolves: active, past_due (retrying, full access retained) and unpaid (dunning exhausted, effective tier drops to the Free contract). Switch state in the header and the usage ceilings move to Free with over-limit treatment, the alert band offers the hosted invoice, and the document row flips to Pay invoice — nothing is deleted and billing stays reachable in every state. Deep-linkable: ?state=retrying / ?state=paused. Mirrors relay-platform RCTX-996 / 997 / 998; documents anticipate RCTX-993.

Checkout & billing profile account · billing · concept

The purchase moment, on the shipped rail as a child of Billing: how you pay, who the invoice is made out to, and what you are buying — one screen, then a success step that replaces it. Its argument is that “for an org/user” is one thing: plan is a property of the org (SPEC.org-plan-model §0), so the billing profile belongs to the personal account or the team workspace being billed, never to the user — the line under the form says which. Two switches, both real axes: the plane (Personal · Pro at $15/mo or Team at $15/seat with the 3-seat floor and a seat stepper that names the true-up) and whether a profile is already on file (saved profiles as radio cards, or the form: me / a business, legal name, tax-ID type + number, contact, invoice email, address). Overview rail with the enforced contract from billing.TIERS, a promotion code, and a period toggle where Annual is disabled and labelled, never selectable — no annual price exists. Built to GUIDE.forms.md: labels, per-field errors on submit, consent that gates an aria-disabled Pay now, and a success step with the same included list, a pending → confirmed status (the plan flip is webhook-confirmed) and the plane’s next actions. Names what the platform lacks: a stored billing profile, an in-app payment element, tax from the address, Team self-serve. Deep links: ?plane=team · ?profile=saved · ?step=success. Record: relay-board/docs/product/checkout-and-billing-profile.md · Linear epic RCTX-1356.

Agent keys connect · security · concept

The credential you hand a headless agent, on the shipped rail as a section of Connect. Its argument is that a key is not a smaller password but a named, narrowed, revocable delegation — so the scope set, the hat and Revoke all sit on the row rather than behind an edit screen. Five scope families (relay:read · claim · send · write, with relay:approve drawn permanently unavailable because an agent cannot satisfy a step-up and could otherwise approve its own requests). The chips carry the distinction the surface exists to make: a hat is a wall, a view is a window — drawn dashed and labelled, because mistaking one for the other is how a key gets handed out wider than intended. Roll is why one-time reveal is honest rather than a trap: the secret is shown at creation and at every roll and never otherwise, and rolling keeps the name, permissions and history while refusing the old secret immediately. Names what is real (the OAuth server already mints and refreshes exactly this credential), what is real and broken (today’s Revoke is cosmetic for MCP — the revoked row goes invisible to the verifier, which mints a replacement for the same live token), and what is only drawn. Mobile composition drawn explicitly, card rows not a table. Deep links: ?view=mint · ?view=reveal · ?view=summary · ?view=mobile. Record: relay-platform/docs/DESIGN-NOTE.agent-session-credentials.md.

Manage subscription stub · poses a decision

Deliberately low-fidelity — the manage half of billing, drawn to pose three questions rather than answer them. The three things a member cannot do in Relay today, each already half-built underneath: cancel (cancel_at_period_end is a real webhook-fed column the app reads only to tell a trial from a subscription — no ends on 11 October, no resume), change plan (upgrade works; downgrade exists nowhere, and one landing under current usage has no defined behaviour — hence a guard that states the excess), and seats, which is the decision: Relay seats are derived from membership by sync_subscription_seats, the reference console assigns them — adopting that means a member can exist without a seat, changing quota reads and the true-up, so both models sit behind one switch. Every action names the analytics event and audit row it writes, because ga4_event() has zero callers today. Deep links: ?seat=assigned · ?state=ending. Record: relay-board/docs/product/subscription-management.md · relay-platform/docs/SPEC.billing-surface-requirements.md.

Team — Roles & groups org RBAC · RCTX-718

Org-admin self-service RBAC (the org plane). Members with base-role dropdowns, org groups (Engineering / Contractors / On-call), and a New-group form whose capability picker locks what you don't hold — the delegation firewall made visible (members.role.assign / owner-only stay locked; platform capabilities never appear). Read-only role reference matrix. The platform plane lives in the console (concepts/console-v35/ → Roles & access). Model: briefs/SPEC.rbac.md.

Org onboarding & residency creation moment · concept

The creation moment, both planes behind one switch — because the argument is that they are one column (orgs.data_region) surfaced twice, not two features. Plane B (team org) is a working 3-step wizard — identity + purpose, people, placement — with the entitlement card pinned throughout: add an invite on step 2 and the Teams quota recomputes live (10 × seats), which is the "computed, never stored" rule being legible rather than described. Plane A (personal org) gets no wizard at all — it is auto-created as personal:{user_id} and single-member by Postgres trigger, so the only question worth asking is the region one. Deliberately not copied from the flow it models: region sits on the org, never the project (per-Project regions would let one org straddle jurisdictions), and step 2 leads with domain autojoin — already built end to end — with email invites as the fallback. Only the two configured regions are selectable; planned ones are shown disabled rather than invented. Draws the live defect honestly: update_user_avatar's region param is never passed, so every avatar lands in the US bucket today (RCTX-892). Closes on the pricing conflict it surfaces — residency selection can't stay Enterprise-gated if Free EU users are to be served. Deep links: ?plane=personal · ?step=3. Plan: relay-board/docs/product/org-management-program-map.md.

Connect tools · RCTX-499

The Connect screen in the shell — a two-act flow that unifies the MCP connector with the universal agent launcher. Act 1: the MCP-URL hero (click-to-copy) + a client picker tiered by install mechanism — one-click deep link (Claude · Cursor · VS Code, + Insiders), copy-a-command CLI (Claude Code), config snippet (ChatGPT, Windsurf, Zed, Kiro, …) — each swapping its setup inline. A live handshake pulse (breathe → check → spark) then reveals Act 2: the shippable launcher, pre-filled with a starter Code. ?state=connected shows the per-agent connection cards; ?theme=dark for dark. Ports connect-experience.html onto the shell. Brief: BRIEF.connect-activation.

Dark theme theme

Every screen in the neutral dark ramp (canvas darkest, cards lighter; teal #2dd4bf, ink-flip buttons). Append ?theme=dark to any prototype.

Concepts in review

Riffing on the same shell anatomy but not yet confirmed into shell.html's canonical nav groups. Moves up into "App shell — as shipped" once the IA is agreed and it's wired into the real rail.

Search v2 — one engine, two mounts concept · interactive · PRD.search-experience-v2

The Search Experience v2 plan (relay-board PRD.search-experience-v2) made clickable: the full /search screen and the ⌘K palette sharing one parser, scorer, and result-row spec. Two-pass results (instant local pass → engine pass merging in), narrowing operators (type: in: status: from: #tag) with live chips, facet rail with honest counts, the annotations the API already computes finally rendered (unread dot, ⚡ agent-touched), Code-status card gated on real intent (an existing Code, or typed uppercase — "deploy" no longer summons a status card over its own results), zero-query discovery (pick up where you left off · unread · agents active now), saved searches + settled-only recents, and the URL as shareable state. Demo hooks: ?q=… · ?cmdk=1 · ?theme=dark. Full light/dark + mobile.

Network concept · connections

Map and manage who you're connected to — people and organizations. "Waiting on you" / "Waiting on them" sections surface pending connection requests, modeling the fix for the approve+connect gap on relay claims: today it auto-links instantly with no second approval; this concept makes the recipient (Ada) accept first, and both sides then see it here as Connected. Built on the confirmed rail/⌘K shell — ties into shell.html's #606 "Org Connections leaves the rail" note as one candidate landing spot.

Network — dark concept · theme

Same concept screen in the neutral dark ramp.

Custody in the app shell concept · interactive · real chrome

The custody flip inside the shipped shell anatomy — real sidebar with a functional workspace switcher (dropdown + [/] cycling, lens-flip transition), topbar with region readout and the bell popover carrying guided switches, and the Transfers screen strictly scoped per context: claim simulator, Pass → across joined workspaces, per-object provenance timelines. This is what RCTX-979 feels like in the actual app. Keys: [ ] · 1-3 · h · b · j/k · o · p · t theme.

Address custody walkthrough v2 concept · interactive · rulings applied

Clickable prototype for SPEC-address-custody-v1 / RCTX-979 with the rulings baked in: strict scoping (v1's blend toggle is resolved and removed), the org-tagged bell with guided switching (tap → lens flips → lands on the item), one-tap Home, per-membership address mapping (1:1 picker), the claim simulator (mapped / unmapped / entitlement-lapsed fallback), and — new in v2 — Pass → between joined workspaces with the per-object timeline carrying provenance across the wall, visible from both sides (data crosses org walls only as a relay). App-side only; console is a separate surface.

Design system: loads the shipped relay-app/packages/ui/tokens.css (copied here as tokens.css) — role-split dual-value teal, neutral surfaces, Cormorant Garamond / Outfit / JetBrains Mono. One universal collapsible rail + top-bar ⌘K search span every screen. Graph and Connect are now live screens in the shell.
Next: Send, Settings, and Catalog have all landed their prototypes. The real screens are ported into relay-app in tandem — Connect's tiered client picker is shipping into #page-connect now.
Archived prototypes (superseded lines, retired explorations) stay listed but visually receded — dashed border, dimmed — rather than deleted, so history isn't lost.