🤖 feat: add an experimental native mobile companion - #4103
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
🤖 Codex-reference navigation and composer polishUpdated in
Before / after
composer-bottom-390.webmVerification
The recording is 24.3 seconds. RN Web evidence only: native keyboard/gesture/device validation remains outstanding. Generated with |
Implement native connection, grouped workspace navigation, conversation streaming and actions, server-backed creation, model settings, read-only changes, and connection settings. The mobile client uses shared API/types and aborts workspace-bound work on navigation. Validation: 15 TS/TSX syntax transforms, formatting, seven settings behavior checks. Full mobile typecheck and visual dogfood depend on the parent scaffold and transport integration.
Add a single authenticated, owned WebSocket connection for unary RPC and subscriptions, with endpoint validation, cancellation, timeout, and no retries. Reduce real chat events into authoritative, immutable mobile transcript state. Validate endpoint security, replay/interruption/truncation behavior, and live oRPC socket authentication, subscription delivery, and mutation lifecycle.
Keep the selected workspace and draft mounted while replacing the closed connection. Abort all prior-connection work, require fresh full replay before chat writes, and cancel late reconnects when disconnecting or unmounting. Warn explicitly before HTTP sends bearer credentials in plaintext. Validation: five reconnect lifecycle tests (28 assertions), 17 TS/TSX syntax checks, formatting and whitespace. Full RN typecheck and UI evidence remain with parent integration.
Isolate native dependencies and shared schema contracts, add secure credentials and a fixed-target Node preview proxy, and validate transport/replay and connection lifecycle behavior. Document native runtime limits and development commands. --- _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$12.95`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=12.95 -->
Fix issues found through React Native Web dogfooding: exclude synthetic scratch projects, use the shared model catalog/defaults, persist effective reasoning defaults, and page older history without resurrecting truncated rows. Include behavioral regressions and synchronize the mobile documentation index. --- _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$36.99`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=36.99 -->
Unify native spacing, type, control/card/sheet radii, and grouped form styling. Keep sheet actions visible, bound web sheets with a dismissible scrim, protect pending workspace creation from dismissal, and require confirmation before disconnecting. Add friendly model search, token visibility, and native keyboard focus progression. Validation: mobile TypeScript, targeted ESLint, formatting, 60 mobile source tests including five isolated RN-Web form behavior cases. Parent owns integrated desktop/mobile screenshot and recording gates.
Replace manual navigation with a native stack, preserve drafts and selections, and refine conversation, workspace, model, and changes layouts. Add pinned-viewport browser regressions, including composer growth/shrink and navigation retention. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high`_ _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$148.33`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=148.33 -->
Show a neutral fallback when an empty persisted assistant row has no interruption marker; preserve explicit interrupted and active-stream behavior. Cover these branches with native-web behavior tests. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high`_ _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$148.33`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=148.33 -->
Render a calmer native transcript with accessible message roles, hanging Markdown lists, readable literal code blocks, and transparent tool/reasoning action rows. Open bounded tool inspection sheets, retain inline question answers, and derive tool state only from real execution/result metadata. Validation: mobile TypeScript, targeted ESLint, formatting, 60 mobile source tests including 13 native-web interaction cases. Parent owns integrated reference screenshots and mobile browser verification.
Use quieter native surfaces and lightweight session navigation, center conversation context, integrate model and send controls into one composer, and progressively disclose thinking settings. Preserve transport, draft/model state, and native navigation; add browser coverage for focused settings. Validated mobile checks, pinned browser viewports, real-server integration, web and iOS Hermes exports, Expo compatibility, and root static checks. Captured reference provenance and real-server UI walkthroughs locally. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high`_ _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$248.65`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=248.65 -->
Use platform-neutral authentication copy in the native app and web development preview. Keep browser-only storage limitations in developer documentation; credential handling is unchanged. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high`_ _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$286.86`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=286.86 -->
Replace the combined conversation settings form with model, mode, and effort picker sheets inspired by the supplied native references. Apply list choices immediately, preserve model/effort when switching mode, and require confirmation only for custom model text. Verify selection behavior, draft retention, narrow/wide layouts, web and iOS exports, and real-server replay. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$347.29`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=347.29 -->
Show the Settings-visible catalog directly in the native model sheet instead of a four-model provider shortlist. Reuse shared routing, catalog-accessibility and OpenAI auth rules; search provider names, friendly names and aliases without resurrecting removed discovery entries. Validate hidden and gateway models, cross-provider selection, draft/effort retention, and phone/wide layouts. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$353.19`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=353.19 -->
Bring phone workspace search and creation into a fixed bottom dock, show project/server context in left-aligned conversation headers, and group navigation actions. Keep the input bottommost with Plan/model controls above it. Expand text entry for focus/drafts while preserving web picker clicks through browser focus retention rather than timers or moving controls below the input. Draw focus on the rounded composer boundary. Validate phone/wide/short layouts, keyboard and pointer picker activation, draft/settings retention, send/interrupt controls, and native bundling. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$428.45`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=428.45 -->
03d2fe7 to
eed1626
Compare
React Native's abort-controller and Expo's static AbortSignal patch do not provide throwIfAborted, which oRPC invokes before sending the initial authenticated request. Add the missing native compatibility method without replacing existing implementations or bypassing cancellation. Reproduce the generic connection error with RN's actual abort implementation and a real WebSocket/oRPC server, then run the transport/auth/cancellation suite in an isolated native-global subprocess. Import the package implementation explicitly because Bun aliases its bare name to the host's modern controller. Validated mobile tests, web/iOS exports, and static checks. Physical-device confirmation remains pending. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$564.47`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=564.47 -->
Use desktop's top-level workspace selector before counting and searching. Share the adjacent-part display projection so persisted stream chunks do not become separate reasoning blocks or paragraphs, without altering authoritative history or tool boundaries. Show the effective reasoning effort beside the model and a compact context ring using desktop token calculations and the latest step's usage. Context respects compaction/reset boundaries, authoritative completion, replay, and deletion rather than accumulating billing totals. Verified red/green native-web behavior regressions, live usage/replay/reset tests, mobile checks, production web export, desktop workspace-filter tests, and root static checks. Native keyboard correction follows separately. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$704.34`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=704.34 -->
Use the SDK-pinned keyboard controller for all four native keyboard boundaries, preserving core web behavior and safe-area layout. Measure window offsets rather than guessing header or sheet insets. Verify the installed overlap algorithm against safe-area and page-sheet geometry, keyboard-height changes, dismissal, and disabled avoidance. Native device positioning still requires iPhone validation. Validation: make -j1 mobile-check (71 passed, 1 existing integration skip); Expo iOS and web exports; web source maps exclude the native keyboard dependencies. --- _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high -->
Use React Native's cross-platform ARIA aliases because RN Web does not forward accessibilityValue. Add a rendering regression for known, over-limit, and unknown percentages. Keep the browser model-preservation assertion on textContent for both its baseline and comparison now that effort is a separate text node. Validation: mobile checks, web/iOS exports, and repository static checks pass after these dogfood fixes. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$713.72`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=713.72 -->
Mobile parity follow-up
Validation: mobile checks 73 passed, 1 opt-in integration skip; web/iOS exports; root static checks; desktop workspace-filter tests; browser E2E 3/3 passed at 375, 390, and 1200px. Red/green regressions cover child counts, chunk grouping, usage replay/reset, ARIA progress values, and native keyboard offset calculations. The browser walkthrough below uses an isolated mock-AI server: one root/five children, raw chunked history, and 200k/1M latest context (20%, distinct from older 60% and cumulative 90%). These are RN Web captures, not physical iPhone keyboard proof. Native keyboard geometry tests use the installed controller with simulated native measurements; the iPhone retry remains necessary. Full-reload unsent state follows the existing in-memory session behavior; Back/reopen retains draft and effort. parity-390.webmGenerated with |
|
@codex review |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 66f68541ae
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…in CI Add one bulk getProjectDiffs operation using validated per-project repo-root execution and fixed git argv with external diff/textconv disabled. Preserve checkout errors and truncation per repository so a clean primary cannot mask secondary changes. Render all results in the mobile changes view. Run mobile-check after the required workflow's root static checks because mobile's isolated graph is excluded there. Document matching client/server revisions for the evolving API. Validation: reproduced the old primary-only false-clean UI; mobile checks and root static checks pass; bulk routing/scratch/truncation/error regressions pass; actionlint/zizmor pass. Real disposable two-repository RPC checks also found secondary changes and did not execute the configured external diff helper. --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$757.08`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=757.08 -->
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cd97460af8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Restrict filename lookup and header filtering to each file's pre-hunk section so source lines beginning with -- or ++ remain visible and counted. Cover multiple hunks, header suppression, and metadata-only changes in the UI. --- _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$1600.29`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=1600.29 -->
🤖 R13 diff-hunk preservation — verifiedSource and immutable export: The Changes view now limits filename/header interpretation to the pre-hunk section. Legitimate deletion/addition payloads beginning Real Git +
Regression first failed because These are RN Web recordings, not native device/simulator validation. The fixture used the unchanged backend, Node preview, owned loopback providers, and telemetry disabled from launch. All owned services/browsers were stopped and fixture ports released. The PR remains draft. Generated with |
|
@codex review |
|
@codex security review |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd0a60cb37
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Keep deleted-checkout transcripts readable without offering a Git action that must fail. Cover disabled navigation, zero diff RPCs, and restoration when the checkout returns. --- _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$1642.49`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=1642.49 -->
Clear persisted and in-memory bearer state on a current ticket-mint 401, then try the ordinary credential-free connection before requiring authentication. Keep retries generation-safe and preserve ticket/cookie security boundaries. --- _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$427.30`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=427.30 -->
Handle Request objects explicitly in ticket-mint fixtures so integrated type-aware lint passes. --- _Generated with `xum` • Model: `coder:openai/gpt-6-astra` • Thinking: `high` • Cost: `$1655.69`_ <!-- mux-attribution: model=coder:openai/gpt-6-astra thinking=high costs=1655.69 -->
|
@codex review |
|
@codex security review |
🤖 R14 auth recovery and read-only Changes — verifiedPublished head: Desktop browser authentication
desktop-recovery-retry.webmdesktop-required-token-negative.webmMobile production RN Web
mobile-missing-checkout.webmLocal gates39 desktop auth/reconnection tests, Fixture correction and validation boundariesThe normal-control fixture initially registered an incorrect persisted workspace path, causing its first diff request to fail. Correcting that owned fixture and refreshing produced the real diff shown above; missing-checkout diff requests remained zero throughout. This is browser/RN Web evidence, not physical iOS or simulator validation. Live filesystem-restoration watcher UAT is not claimed. Generated with |
This comment has been minimized.
This comment has been minimized.
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…port Every call is its own bearer-authenticated request and every subscription its own streamed response; no socket, ticket or per-connection state survives a network change. Streams heal independently with capped backoff and wake on foreground; a dropped conversation resumes from the server cursor and reconciles the suffix atomically instead of replaying the transcript. Native uses expo/fetch for streamed bodies. The desktop web client keeps WebSockets. --- _Generated with `xum` • Model: `anthropic:claude-fable-5-1` • Thinking: `high` • Cost: `$1676.39`_ <!-- mux-attribution: model=anthropic:claude-fable-5-1 thinking=high costs=1676.39 -->
RN Web dogfooding showed six concurrent SSE subscriptions exhausting the browser's HTTP/1.1 per-host pool, so the unary reads of changed snapshots never completed. Add `server.onChanged`, one server stream fanning in config, provider, policy and workspace-metadata changes, shared client-side by every consumer of a client; a conversation now holds that stream plus its own chat stream. The preview proxy also ends the browser response when the upstream stream dies so clients see the drop. --- _Generated with `xum` • Model: `anthropic:claude-fable-5-1` • Thinking: `high` • Cost: `$1704.94`_ <!-- mux-attribution: model=anthropic:claude-fable-5-1 thinking=high costs=1704.94 -->
A dropped change stream withdraws the settings and policy snapshots so sending pauses, but it is not an error: the stream reconnects on its own and the Reconnecting indicator already explains the pause. --- _Generated with `xum` • Model: `anthropic:claude-fable-5-1` • Thinking: `high` • Cost: `$1716.99`_ <!-- mux-attribution: model=anthropic:claude-fable-5-1 thinking=high costs=1716.99 -->
🤖 R15 HTTP transport — verified on RN WebPublished head: Measured transport
transient-outage-no-retry-375.webmconversation-recovery-375.webmrequired-token-negative-390.webmWhat the dogfooding caughtThe first cut held six SSE subscriptions per conversation, which exhausted Chromium's HTTP/1.1 per-origin pool and silently queued the settings reads (Send stayed disabled). That produced the Fixture notesThe loopback provider stub answers only scripted prompts; the "Not Found" assistant rows in the recovery recording come from server-side title generation and auto-retry requests hitting that stub, not from the client transport. This is RN Web evidence; native Generated with |
|
@codex review |
|
@codex security review |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3d401679b2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ears The route now follows live workspace metadata: a transcript-only or removed workspace replaces the diff view instead of refreshing Git into a missing checkout, and restoring the checkout brings it back in place. A stream wake issued while a stream was already dying now skips the first backoff instead of being lost. --- _Generated with `xum` • Model: `anthropic:claude-fable-5-1` • Thinking: `high` • Cost: `$1725.87`_ <!-- mux-attribution: model=anthropic:claude-fable-5-1 thinking=high costs=1725.87 -->
|
@codex review |
|
@codex security review |
















Summary
Add an experimental, remote-first React Native mobile companion in
packages/mobile, built with Expo and isolated from the desktop dependency graph. Execution, Git, terminal, and filesystem tooling remain on an authenticated remote Xum server.Implementation
server.onChangedchange stream (config, providers, policy, workspace metadata; new server procedure) and the conversation'sworkspace.onChat. No socket, ticket, or per-connection state survives a network change; streams heal independently with capped backoff and wake on app foreground, and a dropped conversation resumes from the server's since-cursor with the replayed suffix reconciled atomically instead of replaying the transcript. Native usesexpo/fetchfor streamed bodies; mutations are never retried. Reverse-proxy path support, native SecureStore credentials, and memory-only browser-preview credentials remain. Mobile connections require HTTPS except for same-device loopback development; private LAN HTTP is rejected before any request. The development preview uses a fixed-target proxy without weakening server Origin checks and ends browser responses when an upstream stream dies.Validation
make static-check-full; production RN Web and iOS JS exports.Evidence
Screenshots and videos are RN Web evidence, not simulator/device validation.
HTTP transport: two-stream model, silent outage recovery, since-cursor resume, and token-rejection recordings
Stale-bearer recovery, credential-free Retry, invalid-token gating, and missing-checkout Changes recordings
Real-Git hunk-line preservation, exact counts, deletion, mode changes, and Refresh
TLS rejection, live agent/recovery gating, creation policy, and high-frequency stream recordings
Secure ticket connections, nested replay, composer draft isolation, and pinned desktop meter recordings
Stop/crash recovery, queued questions, live catalogs, and final-field submission recordings
Delegated identity, read-only transcripts, and seeded-prefill recordings
Live-answer, shared-icon, web-keyboard, and merged-settings compatibility recordings
Route/theme projection and final merged User Stop recordings
Fallback attempt accounting and queued-review recovery
Regression risks
The mobile client requires a server exposing
server.onChangedand the desktop web token client requires ticket issuance; older servers must be updated. Mobile connections to other devices, including private LAN hosts, require trusted HTTPS. Mobile subscriptions are long-lived HTTP responses: intermediaries that buffer or time out idle streams would delay live updates until the client's automatic reconnect. Server-side legacy and cookie-only authentication remain supported. Connection lifetime, cancellation, single-use authorization, replay, and context fallback are covered by focused real-network and UI regressions.Draft status / limitations
Generated with
xum• Model:anthropic:claude-fable-5-1• Thinking:high• Cost:$1723.39