Repository navigation
Remote mobile: rewrite the feed rendering (mobile-native, and adopt the new ownership-ledger pipeline) #475
Copy link
Copy link
Closed
Description
Sub-issue of #420 (Remote Mobile Companion). The phone can pair, list sessions, submit prompts, and stream — but the feed rendering is far from done. This tracks a ground-up rework.
Where it stands today (the actual code)
- The phone reuses the DESKTOP
Feedcomponent verbatim.src/remote-client/src/ui/SessionView.tsx:3imports@renderer/features/feed/ui/Feedand renders it, wired via the vite alias table (src/remote-client/vite.config.ts) plus a handful of stubs (stubs/CodeBlock.tsx,SafeInlineCode.tsx,SafeMarkdownLink.tsx,appStateHooks.ts). It feeds the sameSessionFeedchannels the desktop does (src/main/remote/SessionFeedSource.ts→WebSocketSessionFeed). - It renders through the LEGACY path only. SessionView passes
semanticTurn/semanticHistory/toolUseIndex/toolResultIndexas props — there is norenderItemsOverride/useLedgerFeedItemswiring. So the moment the desktop rendering cutover (the new ownership-ledger pipeline, PR feat(rendering): ownership-ledger rendering pipeline + session recording + soak fixes — integration branch #442) lands, the phone is stranded on the renderer being deleted. - Styling is desktop-parity, not mobile-native.
src/remote-client/src/styles.cssis ~174 lines that mostly inherit desktop styles (per PRs fix(remote): client-serving robustness — per-request bundle check, cache headers, self-diagnosing fallback #431/Remote: restart-proof history, richer session picker, desktop style parity #440 "desktop style parity on the phone"). There is almost no mobile-first layout: dense desktop tool rows, marker gutters, collapsed-activity chips, and code blocks were designed for a wide pane with a mouse, not a 390px touch screen.
Why "reuse the desktop Feed" is now the wrong foundation
It was a reasonable bootstrap (ship something fast), but it couples the phone to desktop-shaped rows and, critically, to the legacy renderer that the rewrite is deleting. The desktop feed's density, hover affordances, and fixed-width assumptions don't translate to touch. And the two will diverge hard at cutover.
What "properly done" looks like
- Adopt the new pipeline, don't fork it. The ownership-ledger pipeline (
src/renderer/src/rendering/) is provider-neutral and produces a clean ordered row model (RenderLedger→ view bridge). The phone should consume that decision core and render its OWN mobile row components from it — same ownership/ordering guarantees, different presentation. This is exactly the seam the rewrite created (decision core vs. dumb rows). The phone becomes a second "view" over the ledger, like the desktop view bridge. - Mobile-native row components. Purpose-built for touch/narrow: readable prompt/assistant bubbles, tap-to-expand tool calls (reuse the plan's JSON/MCP tool-row concepts but sized for the phone), collapsed subagent/Task cards, code blocks with horizontal scroll containers, big tap targets. Not the desktop marker-gutter layout shrunk down.
- Reuse the session recorder for mobile fixtures. The Session Recording work (Session Recording: continuous debug-gated capture replayable as rendering fixtures #467) records the SessionFeed input stream — the exact stream the phone consumes. A recording replays through the ledger identically for desktop and phone, so the phone's rendering gets the same replay/invariant test net for free, and mobile-specific divergences become fixtures.
- Handle the mobile-only surfaces properly. Conditions/AskUserQuestion tap-bar (already partially in SessionView), the screen/terminal fallback, connection/restart states, scroll/stick-to-bottom on touch.
Scope / non-goals
- In scope: the feed rendering rewrite for the phone, mobile row components, adopting the ledger decision core, mobile fixtures via recordings.
- Not here: pairing/transport/auth (that's Remote Mobile Companion: control agents from your phone (LAN + optional tunnel) #420 core), which work fine.
- Sequencing: this should land after or alongside the desktop cutover (PR feat(rendering): ownership-ledger rendering pipeline + session recording + soak fixes — integration branch #442) so the phone adopts the ledger rather than chasing the legacy renderer as it's removed.
Pointers
- Phone feed entry:
src/remote-client/src/ui/SessionView.tsx,src/remote-client/src/transcript/store.ts - Server feed:
src/main/remote/SessionFeedSource.ts,RemoteController.ts,WebSocketSessionFeed.ts - The pipeline to adopt:
src/renderer/src/rendering/+docs/rendering/rendering-rewrite-plan-2026-07.md - Recording/replay for fixtures:
docs/rendering/session-recording-plan-2026-07.md(Session Recording: continuous debug-gated capture replayable as rendering fixtures #467) - Umbrella: Remote Mobile Companion: control agents from your phone (LAN + optional tunnel) #420
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
Juliusolsson05 commentedon Jul 9, 2026
Closing — shipped, with one deliberate direction change from this issue's sketch.
What landed:
useLedgerFeedItemsproducer the desktop uses (Stage-3 cutover PR feat(rendering): ledger is sole decision core; migrate phone, kill legacy renderer + flags (Stage 3) #483 migrated the phone off the legacy path when it was deleted; the runtime view is now honestly typed against the declaredRuntimeRenderInputcontract from refactor(layers): declare RuntimeRenderInput — the ledger's licensed input (#493 PR-2) #502).Feed+ row components (five documented stubs), realPaneHeader/ComposerInputchrome, mobile-safe CSS (container-query paddings, horizontal-scroll containment for code/tables, iOS anti-zoom), the conditions tap-bar, and voice dictation (/dictatereusing the desktop STT engine, with secure-context + STT-key gating from the codex review pass).The direction change: this issue prescribed purpose-built mobile-native row components. That was explicitly superseded — the decision (2026-07-08) was a 1:1 replica of the desktop feed reusing our components, precisely so phone and desktop can never diverge in rendering semantics. Same ownership/ordering guarantees, same rows, zero drift surface. The "second view over the ledger" idea survives in the architecture (the view bridge is feed-owned and injectable), so a mobile-native skin remains possible later without touching the decision core.
Mobile fixtures via recordings came free with the shared pipeline: the corpus + replay net exercises the exact
RuntimeRenderInputpath the phone paints from.