RelayCTX / Mirror · mobile PRD · v3 Mobile concept →

Read-only mirror. The source of record is relay-board/docs/product/PRD.mobile-v3.md, behind Cloudflare Access. This copy exists so a concept can be read alongside the scope it is drawn against without board access — it is a projection, never a source.

Rendered 2026-08-18 from relay-board 523b183 · regenerate with python3 scripts/render_prd_mirror.py <board-path> concepts/v40/prd.html

PRD — Relay Mobile v3 (Companion and Custody)

Doc ID: RELAY-MOB-PRD-003
Date: 2026-08-17 · Status: Draft — for ratification · Owner: Erik
Supersedes: RELAY-MOB-PRD-002 (relay 8NHT5P, 2026-06-12) · RELAY-MOB-PRD-001
(relay-app docs/PRD.mobile-v1.md, 2026-06-10)
Concept of record: relay-creative concepts/app-mobile-v2.html · supporting:
shelves-mobile-v1.html, map-mobile-concept.html, app-wearable-v1.html
Interface law: relay-creative guidelines/GUIDE.mobile-composition.md (390px-first)
Programme: Experience 4.0 Pillar 5 — two bodies, one user
Related: Feature Index §3.8 · Sharing Direction
· PRD — Cloud Files · Organizing Layer
· Nudges & Interaction Layer · specs/notification-layer.md
· DECISIONS.md DEC-022, DEC-023, DEC-026, DEC-027

Why this document exists

The authoritative mobile PRD has been living outside git as relay 8NHT5P since June. Every mobile decision cites it; no repo contains it. This document brings the PRD into the estate, folds v1 and v2, and records the scope change EC made on 2026-08-17. From here the board copy is the source of record and the relay is a snapshot of it, not the other way round.

1. What changed, and why

v1 scoped mobile as a five-screen companion: Inbox, Claim, Approve/Deny, Stream glance, Settings. v2 kept that shape, named the three jobs (Act · Aware · Capture), and drew a hard line — "companion, not a port" — explicitly excluding the composer, search, series management and anything admin-shaped.

Two things have since made that line false.

The build already crossed it. Twelve screens ship today, and three of v1's named exclusions are among them — send.tsx is a composer, search.tsx is search, plan.tsx is billing. The largest file in the app, at 449 lines, is requests.tsx: the governance surface. The scope boundary stopped describing the product some time ago and nobody retired it.

The estate's own decisions entail more. DEC-023 rules that the console does not reimplement the app's own-account screens — Profile, Security, Organization, Connect, onboarding and recovery belong to the app, with the console deep-linking in. Experience 4.0 Pillar 5 rules that mobile is a first-class rendering of the same grammar, not a reduced port. Together those already oblige mobile to carry account and governance. Nobody had drawn the consequence.

The v3 position

Mobile is a companion surface for the work and a primary surface for the account. Depth belongs where the user chose to go, not to whichever device they happened to pick up.

v2's three jobs stay intact and stay first. v3 adds the fourth that the build and the decisions already imply.

2. The four jobs

JobWhat it meansPosture
ActApprove or deny what's waiting on you, in seconds, from the notification where the OS allows.Ambient · notification-first
AwareA 5-second read on where things are, with useful context resurfaced through the day.Ambient · glanceable
CaptureSpeak or share a thought on the move. The phone is the sticky note.Ambient · one gesture
AttendHandle things about Relay — your profile, your hats, your library, your people, your plan, your support requests.Deliberate · you navigated here on purpose

Attend is the new one, and the distinction that makes it safe is posture, not depth. Act/Aware/Capture are things that happen to you and must be resolvable in seconds. Attend is what you opened the app to do. A user who taps into workspace management has declared intent, and serving them a deliberately impoverished screen because they are on a phone is the failure GUIDE.mobile-composition.md exists to prevent.

Consequence — the depth rule needs restating

Experience 4.0 §The 4.0 bar, rule 3 currently reads:

taste (MCP) → excerpt (mobile) → full (web app)

As written this makes every Attend screen off-canon. Proposed amendment: depth is a property of the view, not of the surface.

This preserves the rule's real intent (a response that reproduces the app page is at the wrong tier) while removing the reading that mobile is permanently the shallow tier. Ratification required — see §8, D3.

3. As-built inventory (2026-08-17)

Honest state of relay-app/mobile/, so planning starts from the code rather than the PRD.

ScreenLinesWhat it actually isJob
index.tsx346Home — status glance + Today stripAware
notifications.tsx317In-app Needs-You feed + activity. Not push.Act · Aware
requests.tsx449Approve/deny. Largest screen in the app.Act
capture.tsx297Capture inbox + structured draftCapture
send.tsx347Composer with recipient pickerCapture
search.tsx146Global search + Code lookupAware
settings.tsx340Settings; profile edits name onlyAttend
plan.tsx154Plan / billingAttend
graph.tsx491Graph — ego viewAware
connect.tsx176Loop referral programme — see §5—
claim.tsx96Code entry → claimAct
relay/[pin].tsx, transfer/[code].tsx—Relay detailAware
(auth)/, (gate)/—OTP sign-in; NDA/EAPA legal gate—

Not present: push notifications (expo-notifications is not in mobile/package.json — the dependency is not installed), any files/library/shelf surface, any workspace or org switching, any people-connections surface, any support surface.

Design-system state: mobile/lib/theme.ts is a third design system — GitHub-Primer dark (#0d1117, #010409, #30363d), accent #00D9C8 (motion-only under v3.5, and the upstream source of the rogue teal that leaked into web status dots), System/Courier New fonts behind a TODO. Accessibility: one accessibilityLabel across 194 Pressable/TouchableOpacity references. Tracked as RCTX-443 and RCTX-763.

4. Surfaces — and which direction each one travels

The single most useful finding in this rewrite: mobile is not uniformly behind. Three of the surfaces EC named have no implementation on any platform, and their concepts are already drawn at 390px. For those, "port from web" is not a slower path — it is a more expensive one, because composing at desktop width and reducing is exactly what GUIDE.mobile-composition.md forbids.

SurfaceWeb todayMobile todayDirection
Files / Library / ShelfNone — catalog.ts has zero shelf/library referencesNoneMobile-first
Workspace (hats)Functions only, no shell switcherNoneMobile-first
CaptureFollowsShipped, 297 linesMobile-first (already)
Governance / requestsrequests.tsShipped, 449 linesParity — mobile is strong
Profileprofile.ts, handle-profile.tsName onlyPort to mobile
Connections (people)connections.ts, network.tsNonePort to mobile
Relay quick-infoPartialDetail screen onlyBlocked on a ruling
Support3 report sinks + FreshdeskNoneNew on both

4.1 Files / Library / Shelf — mobile-first

The nouns settled 2026-08-08 — Library (container) / Shelf (set), display-layer only. The schema landed. PRD — Cloud Files is written and awaiting ratification. Concepts exist for desktop (files-v3.html, app-v35/files.html), for governance (console-v35/org-ia.html) — and for the phone (shelves-mobile-v1.html). What does not exist is a single line of surface code, on either platform.

Build the 390px composition first and let desktop earn the extra space. This is the law as written, not an exception to it.

Hard problem, stated honestly: browsing is table-shaped, and tables are the worst case at 390px against a law that bans chip walls, caps chrome at two rows, and demands content hold ≥70% of the fold. shelves-mobile-v1.html and the console's shared DataTable are the two pieces of prior art; neither has been proven at volume. The regime table (BRIEF.context-map-density.md, ~50 / ~500 / ~5,000 objects, phone column first) is a dependency, not a nicety.

Precise state:

Do not mistake account switching for hat switching

Mobile shipped multi-account switching (mobile/lib/session.ts, context/SessionContext.tsx, SecureStore — see relay-app docs/DESIGN-NOTE.mobile-account-switching.md). That moves between your Relay accounts. A hat is a workspace boundary inside one account. The two are different axes and the shipped one is easily read as covering both. It does not.

v2 put multi-workspace switching out of scope, reasoning: "tied to unresolved user/org architecture issues; revisit when that lands." That blocker has cleared — workspace custody is live on the backend, feature-gated, with zero app surfacing. The deferral was correct in June and is stale now.

Because no surface exists anywhere, mobile can ship the first hat switcher, and the touch target is the honest test of the concept: a hat that seals rather than filters, where positions never move (hats-and-lenses-v1.html; the v40 app concept already makes hats touchable).

4.3 Connections — a port, blocked by its own name

Mobile has no people-connections surface. connect.tsx is the Loop founding-member referral programme (loopApi, referral code, short URL, sponsor email).

"Connect" names three unrelated products across the estate:

MeaningWhere it lives
Connector setup (MCP host handshake)web connect-wizard.ts, connect-panel.ts, connect-catalog.ts; Connect × Activation
Loop referral programmemobile connect.tsx
Connections / peopleweb connections.ts, network.ts

This is worse than the "lens" drift the lens glossary is meant to fix: there, one word carried seven shades of one concept; here one word names three different products, and the phone shows the least common of them.

Proposed resolution — folds into the lens-glossary ratification (Wave 0 #3), enforced by relay-creative scripts/check_vocab.py:

Gating collision

relay-app gating.ts's streamlined preset hides network, team, contract and refer for curated cohorts. If Network becomes a core mobile job it lands on a surface switched off for exactly the users being onboarded most carefully. Resolve when Network ships on mobile — either Network leaves the streamlined hide-list, or mobile respects it and the job is scoped to non-streamlined users.

4.4 Relay quick-info — blocked on a ruling, not on code

"See useful information about a relay you have access to, without claiming it" is the document reading of the view tier. DEC-027 shipped enforcement (view = read-only at the claim gate, with grandfathering), but Sharing Direction — document vs handoff — is decision pending, gate RCTX-1259, with the groups UI and share-dialog tracks (RCTX-1260/1262) behind it.

Any mobile preview surface built before that ruling is building on an unratified model. No mobile work starts here until RCTX-1259 lands.

4.5 Profile — straight parity work

Mobile Settings shows email display-only and edits name alone; UpdateProfileRequest carries no email field. Bring over the additional-emails list with Verified / Pending / Backup state, add-email → OTP verify, handle management. Tracked as RCTX-373, spec at specs/profile-page-spec.md. Well-understood; no decisions required.

4.6 Support — new on both surfaces

Act/Aware/Capture never had a support leg. The platform has a Freshdesk integration (src/relay/freshdesk.py) and web has three report sinks — faults → frontend-error, refusals → gate-denied, wrong content → /feedback. None of it reaches the phone.

That is backwards. The phone is where you are when something breaks and you are away from the desk, and a support request raised there can carry device, build, session and the object you were looking at without asking the user for any of it. Scope for v3: raise a request with automatic context attachment, see its status, respond. Not a helpdesk.

5. The notification layer is the spine

Every ambient job depends on one unbuilt system, and it is the smallest genuinely-new platform piece in the programme.

Already live. The nudge engine runs and emits typed, prioritised, deep-linked signals — closing_relay (p1), expiring_series (p1), unclaimed (p2), unread_inbound (p2), each with text and a cta_url. specs/notification-layer.md has the right architecture: one signal layer, N delivery channels, with nudges.py computing identically across channels and only delivery differing. Sources are already unified — nudges, fired Cues, maintenance, inbox/claim-approval, A2A push. The payload exists; only transport is missing.

Absent. expo-notifications is not installed. No device-token registry, no APNs/FCM wiring. specs/notification-layer.md has been Draft since 2026-06-21.

Triple-filed. Three overlapping Linear issues must collapse to one before anyone starts, or the work forks:

IssueTitleState
RCTX-341Mobile V1 P0: push infrastructure (APNs/FCM + device token registry)Urgent · Mobile App
RCTX-459Epic · Notification layer — push + nudge delivery (web/mobile/MCP)High · Phase A milestone
RCTX-467Epic: Notification layer — APNs/FCM + nudge delivery, one pipeHigh · no project

RCTX-459 and RCTX-467 were filed 2026-07-10 seven minutes apart and say the same thing. Recommendation: keep RCTX-459 (it carries the Phase A milestone and the project), close RCTX-467 as duplicate, and make RCTX-341 a child of RCTX-459.

Downstream dependency: the number-match push 2FA in the concept (RCTX-64 / RCTX-134) cannot function without this layer. It is not a parallel track.

6. Navigation — the ruling this document needs

Three artefacts currently disagree while DEC-022 reads as settled:

Recommendation: adopt the drawer. DEC-022 stands, no exception.

When mobile did three jobs, a companion-posture exception was defensible. The v3 scope removes that argument arithmetically. Destinations under v3: Home · Activity · Capture · Search · Files/Library · Explore/Graph · Requests · Network · Profile · Workspace · Plan · Support. That is twelve. The concept already had to demote "You" into a Menu sheet to avoid a fifth screen with only five destinations competing.

A drawer scales; five tabs do not. The exception was justified by narrow scope, and the scope just widened.

Land it in one PR or it just moves

Whichever way this rules, it must change DEC-022, this PRD, and concepts/app-mobile-v2.html in the same PR. Three artefacts disagreeing is the current failure; fixing two of three reproduces it.

Retained from the concept regardless of ruling: Menu-as-sheet (slides over the current screen, never navigates away), the persistent bell sharing Activity's badge, and Activity as one unified space for notifications and feed — which is also the two-inbox ruling (Wave 0 #6) already answered correctly on mobile.

7. Phasing

Resequenced from v2. The change: Files/Shelves and the hat switcher leave 4.0's Wave 3 ("port the native app"), because there is no web surface to port and the concepts are already drawn at 390px.

PhaseScopeGate to advance
A — The spineNotification layer end-to-end (registry, APNs/FCM, delivery rules, per-category prefs, quiet hours); inline approve/deny from the shade; resurface_at scheduled deliveryNotification → decision under 15s, measured. Mute rate instrumented.
A′ — Shell + system (parallel, no dependency)Nav ruling applied; v3.5 token port (RCTX-443); accessibility labelling pass (RCTX-763)Zero unratified nav forks; every control labelled; dual theme correct
B — Attend I: accountProfile parity (RCTX-373); Security (passkey, sessions, device management); Plan; Support intake with auto-contextSelf-serve account management with no web round-trip
C — Attend II: hatsWorkspace/hat switcher — the estate's first; shell re-gating on switch; org switchingA hat switch re-gates the shell and positions never move
D — Attend III: libraryFiles / Library / Shelf browsing at 390px, desktop followingRegime table passed at ~50 / ~500 / ~5,000; first-time viewer finds a tap target within 5s
E — Network + depthNetwork (people) after the naming resolution; provenance timeline; relay quick-info if RCTX-1259 has ruled; analytics cardsNaming enforced by check_vocab.py; no surface on an unratified model
F — StorePolish, a11y audit pass, App Store reviewSee hard gates below

Hard gates, regardless of phase

8. Decisions required

Nothing in §7 past phase A′ can be scheduled until these land. All are ratifications.

#DecisionGatesRecommendation
D1Mobile nav — DEC-022 exception, or drawer adoptionThe native shell. Phase A′ is otherwise build-ready; this is the only hold.Drawer. See §6.
D2Scope — is Attend accepted as a fourth job?This entire documentAccept; it ratifies what shipped
D3Depth rule — depth per view, not per surfaceEvery Attend screen's canon-complianceAccept the amendment (§2)
D4Connect naming — Connect / Network / LoopMobile Network work; folds into the lens glossaryAccept; rename connect.tsx → loop.tsx
D5RCTX-1259 — document vs handoff for the view tierRelay quick-info on every surfaceOut of scope here — Sharing Direction owns it
D6Notification epics — collapse 341 / 459 / 467Phase AKeep 459, close 467, 341 becomes a child
D7Streamlined × Network — does Network leave the hide-list?Phase EDecide when Network ships
D8Patent provisional — assign counsel, filePhase FNeeds an owner and a date

9. Success criteria

Carried from v2 where still valid, extended for Attend.

10. Carried forward from v2 (still valid)

Superseded from v2

11. Known defects in the current artefacts

Found while reconciling; each needs a fix in its own repo.

DefectWhereFix
Copy states "Codes are 6–8 characters" — canon is 4–16 accepted, 10 minted, never hardcode a lengthrelay-creative concepts/app-mobile-v2.htmlCorrect the string. This rule already cost a bug — relay-app a43470a (#707)
Rollout-plan pointer resolves to nothing (product/Relay - Mobile V1 - Rollout Concept.md; no product/ dir exists)relay-creative briefs/BRIEF.mobile-v1.mdRepoint at this PRD
Mobile absent from the capability roll-updocs/product/feature-index.mdFixed in this change — §3.8 added
Stale: "Beta · Apr 30 2026", mobile v2 parked in a Sep 30 2026 roadmap row; untouched since the 2026-04-29 migrationdocs/PRODUCT.mdPartially fixed in this change — mobile row corrected; the rest needs its own pass
Retired vocabulary in live concepts: app-mobile-v2.html ("Relay Code" ×1, "pulse" ×2), mobile-v1.html ("PIN" ×1), map-mobile-concept.html ("Little Rocket" ×1)relay-creativeIn vocab-baseline.txt, so CI is green. Burn down and re-baseline
Concept header badges "Design system v3.5"; the build is Primer-dark v3.4-eraconcepts/app-mobile-v2.htmlCorrect as a specification; misleading as a status label

Confidential — Relay Context Inc.

v4.0 index → Mobile concept → Creative brief → All concepts →