Relay works where your AI works.
The live Connect page, redrawn as it is today, with two things on top: a getting-started card that explains the surface once and retires itself the moment you are connected, and Discover / Manage tabs whose count is the connections Relay already knows about. The shape is Calendly's integrations page; everything underneath it is Relay's own catalog and Sessions list, unchanged.
Connect
One server URL. Any MCP client.Relay works where your AI works.
Connect Relay once, inside the tool you already use. Claude, Cursor, VS Code, ChatGPT, and any MCP client. Nothing to install, no API key.
See every clientRelay is a remote MCP server — nothing to install and no API key. Tell us what you use and we’ll walk you through it.
Stuck? Email support@relayctx.com and say which client you’re using.
Everything inside the frame below the tabs is prod copy and prod structure — connectWizard.* and connectPage.* strings, the 15-entry catalog in connect-catalog.ts, the Sessions list from security.ts. The per-client steps are left out of the reference list here; they come from the catalog unchanged.
One card, keyed to one stage.
The card is not a banner. It is the connected stage of the onboarding ladder (relay-platform docs/DESIGN-NOTE.onboarding-ladder.md) shown on the surface that stage belongs to, and it has exactly three states.
| State | When | Discover | Manage |
|---|---|---|---|
| Not yet | No non-revoked connection and the card not dismissed | Card shows above the wizard | Manage (0), no check |
| Dismissed | The × was tapped before connecting | Card gone; the wizard is the page. Stays gone on this device, like the onboarding brief's seen flag | Manage (0), no check |
| Connected | ≥ 1 non-revoked connection — the same row the Connect page's live watch already detects | Card retires itself; the wizard shows its done pane | Manage (n) ✓, the list with Revoke |
The has-content guard holds. A person with three connections never sees "Connect Relay once" — the card's own condition is the guard (guidelines/GUIDE.states-and-language.md: intro copy must never render over a non-empty collection).
Each surface gets its own card, and only until its stage.
Calendly's page shows the pattern on one area. The ladder note's §8 asks for the onboarding state to reach every area of the app, and this is what that looks like: a card per surface, each keyed to the stage that surface is for, each retiring itself on the stored stamp. Connect is first because its stage is already stored (the first connection stamps funnel step 1 today). The rest follow once onboarding_stage lands.
| Area | Stage it keys to | The card's one line | The tab's count |
|---|---|---|---|
| Connect | connected — stored today | Relay works where your AI works. | Connected clients |
| Relays | sent | Context goes out as a Code. The first one is waiting for you. | Relays you hold |
| Sessions | handed_off | A session ends. The work in it doesn't have to. | Open sessions |
| Streams | streamed | A Stream keeps relays and sessions on one thread. | Streams |
The three lower lines are placeholders for the voice pass, not copy. The Connect line is the one this page argues for.
One relay-app pull request. No migration.
web/index.html#page-connect: the wizard card and the All-clients card become the Discover panel; the Sessions card becomes the Manage panel; the orientation card goes above the wizard withdata-i18nkeys.web/src/connect-wizard.tsmountConnectWizard: tab wiring (role=tablist, arrow keys,#managedeep link) and the card's dismiss, persisted the wayonboarding.tspersists the brief's seen flag.web/src/security.tsloadMcpConnectionsalready fetches/api/user/v1/connectionsand drops revoked rows — it hands the count to the tab. The page's live watch already fires on a new row; that callback retires the card and bumps the count.web/src/locales/en.json:connectPage.tabDiscover,tabManage,orientEyebrow,orientTitle,orientBody,orientLink,orientDismiss, and the Manage empty state.CHANGELOG.mdline in the same PR;npm run typecheckis the gate.
- Slice 1 needs no server change. The connections endpoint returns
active,revoked,client_typeandlast_seenper row, anddb.create_connectionstamps funnel step 1 on the first one. The truth the card needs is already stored. - Slice 2 — the stage. When the ladder's
onboarding_stagelands (relay-platform #2519), the card's condition reads the stage instead of counting rows, and the same component takes a stage name per area. - Slice 3 — the other areas. Relays, Sessions, Streams get their card from the table above, each behind the has-content guard.
- One rename rides along. The Connect page calls MCP connections "Sessions", and Relay's product object is also a Session (
sessions.ts). Under a Manage tab the card can be called what it is: Connected clients. The word Session goes back to meaning one thing. - One small truth fix. The list's glyph should come from the catalog by
client_type; today it knows three icons and falls back to a hexagon for everything else.
Mechanism, then the next action.
| Slot | Copy | Why this and not the obvious thing |
|---|---|---|
| Eyebrow | Getting started | Same words as the app's own onboarding page, so the card reads as a piece of that, not a promotion. |
| Headline | Relay works where your AI works. | True at the point of use: the catalog under it is the proof. The board's stronger line — Relay works even where your AI doesn't (relay-board docs/strategy/shelves-as-primitive.md) — is the reach argument for decks; it would be a claim here, not a description. |
| Body | Connect Relay once, inside the tool you already use. Claude, Cursor, VS Code, ChatGPT, and any MCP client. Nothing to install, no API key. | Names the clients the pills show. "Nothing to install and no API key" is the wizard's own line, kept. |
| Link | See every client | "Learn more" is on the never-list (_vocab/_VOCAB.md). The link names what it opens. |
| Tabs | Discover (14) · Manage (n) ✓ | 14 named clients; "Something else" is a route, not a client. The check is the stage, not decoration. |
| Manage, empty | No clients connected yet. Pick your app under Discover and Relay walks you through adding it. — Discover clients | A never-had-any empty: what this is for, then the first action. Prod's "Connect a client using the setup guide above" points at a guide that is now on another tab. |
| Dismiss | × · "Dismiss this card" | The × is the one Calendly affordance kept verbatim; it has a label and a 36 px target. |
Checked against the voice guide: no word from the never table, no Code length, the headline is a statement of where the mechanism runs and the card closes on an action.
Three things to decide, none blocking slice 1.
- Where "dismissed" lives. Per device (localStorage, as the brief does today) ships now; per account needs a one-column flag and arrives with the stage in slice 2. Recommendation: per device now, move it with the stage.
- The rename. "Sessions" → "Connected clients" on this page only, so Session means the product object everywhere else. Recommendation: yes, in the same PR.
- The headline on the Overview. The onboarding brief already carries "Your context, waiting on the other side." This card carries the Connect line. Two lines, two surfaces, one register — or one line everywhere. Recommendation: two, each true to its surface.