Mobile App (jarvis-node-mobile)¶
The Jarvis Automation mobile app is built with Expo/React Native and runs on iOS and Android. It is the companion app for chatting with Jarvis, setting up and managing voice nodes, receiving notifications, and browsing deep research results. It talks to one server: jarvisd, the Jarvis Automation server.
Jarvis Automation is a pre-release (release candidate rc18.17). Server builds are on the releases page; each one is marked Pre-release. Get the app from the App Store or Google Play.
Connect to your server¶
The app asks for one address, the server's, and finds everything else from it:
- On the first screen, tap Set Server URL.
- Enter
http://<server>:7700, where<server>is the IP address or hostname of the machine runningjarvisd(for examplehttp://192.168.1.100:7700), and tap Save. - Log In, or Create Account with an invite code from a household admin. Only the first account on a new server can sign up without one (see Authentication).
The app does not search the network for the server: the address you pin is the only one it uses, so it never connects to a different server than the one it shows. To change it later, tap the address on the first screen, or use Settings → Config Service URL. If the app says it can't reach the server, check that the phone is on the same network and run jarvisd doctor on the server.
When the app sets up a voice node, it gives the node this same address.
Features¶
- Node provisioning -- set up new Pi nodes over their Wi-Fi hotspot and give them your Wi-Fi and the server's address (see Provisioning)
- Settings sync -- View and edit node command settings via encrypted snapshots (K2 key)
- Push notifications -- Receive alerts from Jarvis (sent by
jarvisdthrough the push relay) - Inbox -- Browse deep research results and other long-form content
- Home Assistant -- Device discovery and smart home control
- Node management -- View paired nodes, rooms, and device status
Screenshots¶
Tech Stack¶
| Technology | Version | Purpose |
|---|---|---|
| Expo | 54 | Build toolchain and native modules |
| React Native | 0.81 | Cross-platform UI |
| React | 19 | Component framework |
| TypeScript | — | Type safety |
| React Navigation 7 | — | Bottom tabs + native stacks |
| React Native Paper | — | Material Design UI components |
| React Query 5 | — | Server state management |
| expo-camera | — | Scanning K2 key backup QR codes |
| expo-secure-store | — | Token storage in platform keychain |
Architecture¶
jarvis-node-mobile/
├── App.tsx # Root providers (Auth, Config, Theme, Query)
├── src/
│ ├── auth/ # AuthContext, token management
│ ├── screens/
│ │ ├── Auth/ # Login, registration
│ │ ├── Home/ # Main dashboard
│ │ ├── Devices/ # Smart-home devices
│ │ ├── Provisioning/ # Node setup flow
│ │ ├── SmartHome/ # Home Assistant integration
│ │ ├── ImportKey/ # K2 key import
│ │ ├── Inbox/ # Inbox items and their screens
│ │ ├── Nodes/ # Nodes tab, node detail and settings, Add a computer
│ │ ├── Routines/ # Routines tab
│ │ ├── Schedules/ # Scheduled errands
│ │ ├── Store/ # Pantry tab
│ │ ├── Memories/, Phonebook/, CallContext/, RecentCommands/, CommandData/
│ │ └── Settings/ # App settings
│ ├── navigation/ # Tab layout + stack navigators
│ ├── services/
│ │ ├── configDiscoveryService.ts # Resolve services from the pinned server URL
│ │ ├── configPushService.ts # Push config to nodes
│ │ ├── haApiService.ts # Home Assistant API
│ │ ├── haDiscoveryService.ts # HA auto-discovery
│ │ ├── oauthService.ts # OAuth flows for commands
│ │ └── qrImportService.ts # QR code parsing
│ ├── components/ # Reusable UI components
│ ├── contexts/ # ConfigContext (global config state)
│ ├── hooks/ # Custom React hooks
│ └── api/ # API clients
├── modules/
│ └── jarvis-crypto/ # Native encryption module
└── __tests__/ # Jest test suite
Settings Sync (K2 Encryption)¶
The mobile app and Pi Zero nodes share a symmetric encryption key called K2 (AES-256). This key is exchanged during provisioning and used to encrypt settings snapshots in transit.
The flow:
- User taps a node in the mobile app to view its settings
- Mobile requests a snapshot from the server
- The server notifies the node via MQTT
- Node builds a settings snapshot, encrypts it with K2, uploads it to the server
- Mobile polls for the snapshot, decrypts with K2, and displays the settings
For development, generate K2 manually:
Then import the key into the mobile app via the Import Key screen (Nodes tab > Import Key > paste the base64url string in the DEV input).
OAuth Flow Execution¶
Some commands require OAuth tokens (e.g., email, calendar). The mobile app handles the OAuth authorization flow:
- The server reports that a command needs OAuth
- Mobile app opens the OAuth provider's authorization URL
- User grants access in the browser
- Mobile app captures the redirect and finishes the flow for that provider
How the tokens are handled depends on the provider. For Home Assistant, the app itself exchanges the code with Home Assistant and creates a long-lived access token, which it uses to import your devices, so for that provider the tokens pass through the app.
Push Notifications¶
The mobile app registers for push notifications with jarvisd:
- App registers its Expo push token with the server
- Jarvis sends notifications (e.g., deep research complete, timer alerts)
jarvisdforwards them to the push relay (jarvis-notifications-relay) for Expo Push API delivery- User taps the notification to open the relevant screen (e.g., inbox detail)
Inbox¶
The Inbox tab displays long-form results from deep research queries and other asynchronous operations. Items are stored on jarvisd and fetched over its REST API.
Development¶
# Install dependencies
npm install
# Start Expo dev server
npm start
# Run on iOS Simulator
npm run ios
# Run on Android Emulator
npm run android
# Run tests
npm test
npm run test:coverage
E2E / CI server URL (EXPO_PUBLIC_MANUAL_CONFIG_URL)¶
The app has no network discovery: it resolves every service from the server URL the user pinned. In DEV_MODE only, a build with no pinned URL falls back to a baked one, so a fresh clearState e2e build can still reach the server in CI.
Set EXPO_PUBLIC_MANUAL_CONFIG_URL to the server's base URL (port 7700) before building. The development-e2e EAS profile sets this automatically:
URL priority order (DEV_MODE only):
- UI-pinned URL (AsyncStorage) — always wins; a developer's manually-pinned URL is never overridden
EXPO_PUBLIC_MANUAL_CONFIG_URL— baked fallback for e2e / CI builds with no pinned URL
With neither, the app asks for a URL. This variable is inert in production builds: DEV_MODE is false and production EAS profiles never set EXPO_PUBLIC_MANUAL_CONFIG_URL.
What the app reaches¶
Everything is on the one jarvisd server. The app starts from the address you pinned (port 7700), which tells it where the rest is.
| Port | Required | Purpose |
|---|---|---|
| 7700 | Yes | The server address you enter; it lists the other services |
| Sign-in, from 7700 | Yes | Login, token management |
| Others, from 7700 | No | Node registration and settings sync, push notifications and the inbox |