Part of Epic #3351 — mobile client support (iOS + Android via Tauri 2).
Problem
The desktop dashboard auto-discovers the local daemon at 127.0.0.1:4545. On mobile this assumption breaks: the daemon runs on the user's home server / VPS / NAS / desktop, the phone is on a different network, and there is no localhost to fall back to. Without an explicit connection wizard the mobile app cannot do anything on first launch.
Approach
A first-run wizard captures (base_url, api_key) and persists them in a platform-appropriate secure store. Three input methods, in order of effort:
- Manual entry — base URL + API key text inputs. Floor.
- QR pairing — desktop generates a one-time QR encoding
{base_url, api_key, expires_at}; phone scans with the camera. Removes typing 64-char keys on a phone keyboard.
- mDNS / Bonjour discovery — when phone and daemon are on the same LAN, surface "Found daemon at homeserver.local" as a one-tap option. Nice-to-have, defer if integrating Tauri's mobile mDNS plugin is painful.
After connection: a connection-health screen showing daemon version, agent count, and a "Reconnect" button. If the daemon is unreachable on app foreground, surface a clear "offline" banner with a retry — do not silently fail.
Tasks
- New page
connect/ in the dashboard with manual-entry form. Hide on desktop builds (cfg-gated render).
- Persist credentials via
tauri-plugin-stronghold or tauri-plugin-keyring — whichever has the cleanest mobile story. Plain localStorage is unacceptable: API keys must not survive a backup-and-restore in clear text.
- QR generation in dashboard: new desktop-only route
/settings/mobile-pairing that mints a short-lived (5 min) pairing token, signs it with the existing API key, and renders a QR. New API endpoint POST /api/pairing/tokens with TTL + single-use semantics.
- QR scanning on mobile: integrate
tauri-plugin-barcode-scanner (or equivalent). Camera permission prompt copy must be explicit about "we read a one-time pairing code, not photos."
- Connection-health screen: pings
/api/health, shows version + uptime + agent count from /api/agents. Re-pings on app_resume (Tauri lifecycle event).
- Offline banner:
react-query onError falls into a top-level <OfflineBanner> with retry; auto-dismisses on next successful query.
- Logout path that clears the secure store and returns to the connect wizard.
Acceptance criteria
mDNS discovery is out of scope for this issue; track as a follow-up after the manual + QR paths ship and have real users.
Depends on #3342. Runs in parallel with #3343.
Part of Epic #3351 — mobile client support (iOS + Android via Tauri 2).
Problem
The desktop dashboard auto-discovers the local daemon at
127.0.0.1:4545. On mobile this assumption breaks: the daemon runs on the user's home server / VPS / NAS / desktop, the phone is on a different network, and there is nolocalhostto fall back to. Without an explicit connection wizard the mobile app cannot do anything on first launch.Approach
A first-run wizard captures
(base_url, api_key)and persists them in a platform-appropriate secure store. Three input methods, in order of effort:{base_url, api_key, expires_at}; phone scans with the camera. Removes typing 64-char keys on a phone keyboard.After connection: a connection-health screen showing daemon version, agent count, and a "Reconnect" button. If the daemon is unreachable on app foreground, surface a clear "offline" banner with a retry — do not silently fail.
Tasks
connect/in the dashboard with manual-entry form. Hide on desktop builds (cfg-gated render).tauri-plugin-strongholdortauri-plugin-keyring— whichever has the cleanest mobile story. PlainlocalStorageis unacceptable: API keys must not survive a backup-and-restore in clear text./settings/mobile-pairingthat mints a short-lived (5 min) pairing token, signs it with the existing API key, and renders a QR. New API endpointPOST /api/pairing/tokenswith TTL + single-use semantics.tauri-plugin-barcode-scanner(or equivalent). Camera permission prompt copy must be explicit about "we read a one-time pairing code, not photos."/api/health, shows version + uptime + agent count from/api/agents. Re-pings onapp_resume(Tauri lifecycle event).react-queryonErrorfalls into a top-level<OfflineBanner>with retry; auto-dismisses on next successful query.Acceptance criteria
tauri-plugin-stronghold/tauri-plugin-keyring— verified by inspecting app sandbox, not in a plain JSON file.410 Gone./settings/mobile-pairingexists and renders a QR; the connect wizard route is hidden / never rendered (no regression).mDNS discovery is out of scope for this issue; track as a follow-up after the manual + QR paths ship and have real users.
Depends on #3342. Runs in parallel with #3343.