# PAILot Flutter - TODO ## High Priority ### MQTT Protocol Migration — NEXT MAJOR TASK Replace ad-hoc WebSocket protocol with MQTT for reliable, ordered messaging. **Why:** Current protocol has no delivery guarantees, no message ordering, no offline queuing. Messages get lost on daemon restart, duplicated on catch_up, and arrive out of order. **Server (AIBroker):** - Embed MQTT broker (aedes) in daemon alongside existing WebSocket - Topics: `pailot/{sessionId}/out` (server→app), `pailot/{sessionId}/in` (app→server) - System topics: `pailot/sessions`, `pailot/status`, `pailot/typing/{sessionId}` - QoS 1 (at-least-once) for messages, QoS 0 for typing indicators - Retained messages for session list and last screenshot - Clean session=false so broker queues messages for offline clients - Bridge MQTT messages to/from existing AIBP routing **Flutter App:** - Replace WebSocket client with mqtt_client package - Subscribe to `pailot/+/out` for all session messages - Publish to `pailot/{sessionId}/in` for user messages - Message ID-based dedup (MQTT can deliver duplicates with QoS 1) - Ordered by broker — no client-side sorting needed - Offline messages delivered automatically on reconnect **Migration:** - Phase 1: Add MQTT alongside WebSocket, dual-publish - Phase 2: Flutter app switches to MQTT - Phase 3: Remove WebSocket from PAILot gateway ## Pending Features ### File Transfer (send/receive arbitrary files) - File picker in app (PDFs, Word docs, attachments, etc.) - New `file` message type in WebSocket protocol - Gateway handler to save received files and route to session - Session can send files back via `pailot_send_file` - Display file attachments in chat bubbles (icon + filename + tap to open) ### Voice+Image Combined Message - When voice caption is recorded with images, hold images on server until voice transcript arrives - Deliver transcript + images together as one message to Claude - Ensures voice prefix sets reply channel correctly ### Push Notifications (iOS APNs) — NEXT SESSION with user at computer - **Step 1**: User creates APNs key in Apple Developer Portal (needs login) - **Step 2**: Save `.p8` key to `~/.aibroker/apns-key.p8`, add env vars (key ID, team ID) - **Step 3**: Server-side APNs HTTP/2 sender (`src/daemon/apns.ts`) with JWT auth - **Step 4**: App sends device token on WebSocket connect - **Step 5**: Gateway buffers messages when no WS clients, sends push notification - **Step 6**: App receives push → user taps → opens app → catch_up drains messages - Optional: silent push to wake app briefly for critical messages ### App Name Renaming (Runner → PAILot) - Rename Xcode target from Runner to PAILot (like Glidr did) - Update scheme names, bundle paths ## Known Issues ### Audio - Background audio may not survive full app termination (only screen lock) - Audio session category may conflict with phone calls ### UI - Launch image still uses default Flutter placeholder - No app splash screen with PAILot branding ### Navigation - vi keys (0, G, dd) are sent as literal text paste — works for Claude Code but may not for other terminals