docs: make Android native app the primary target

This commit is contained in:
Hermes Agent
2026-07-09 03:50:27 +00:00
parent 2cd4730324
commit deec0c7fa3
6 changed files with 166 additions and 80 deletions
+125 -49
View File
@@ -1,43 +1,96 @@
# Mobile App Plan
## App Type
## App Type Decision
Start as a PWA optimized for Android Chrome.
Build Hermes Mobile as a native Android app from the start, using Capacitor around a shared React UI.
Why PWA first:
- Fast iteration.
- Easy self-hosting.
- No app store.
- Installable to home screen.
- Web Push support on Android is good.
- Same frontend can later be wrapped with Capacitor.
PWA will still exist as a fallback/dev target, but it should not be the primary product experience.
Potential later native shell:
- Capacitor Android for native share target, richer notifications, and better file/mic APIs.
## Why Native Android First
A PWA can get surprisingly far on Android: installable icon, offline shell, camera/mic, file picker, Web Push, and a standalone window. But for this project, “suffices” is not the bar. The goal is that Hermes feels like a genuine phone app designed around agent work.
Native Android via Capacitor gives us:
- Real APK install path.
- Native splash screen and status bar control.
- More reliable push notifications.
- Better haptics.
- Better file/share integration.
- Easier future “Share to Hermes” target from Android apps.
- Better control over permissions and app lifecycle.
- Native-feeling back button behavior.
- More credible “this is an app” feel than browser-installed PWA.
## Role of PWA
Keep PWA support for:
- Fast development loop.
- Desktop/LAN access.
- Emergency fallback if APK is not installed.
- Users who do not want to sideload.
But feature priority should be:
1. Android app / Capacitor
2. PWA fallback
3. Desktop web convenience
## Frontend Stack
Recommended:
- Vite + React + TypeScript
- Tailwind CSS
- Capacitor Android
- TanStack Query for server data
- Zustand for local UI/session state
- Framer Motion for motion where useful
- Workbox or Vite PWA plugin
- Framer Motion for app-like motion where useful
- Zod for API schema validation
- Vite PWA plugin for fallback web install
Alternative:
- Next.js if SSR/server components become useful, but for a companion-served app Vite is simpler.
Capacitor plugins:
- `@capacitor/android`
- `@capacitor/app` for lifecycle/back button
- `@capacitor/haptics`
- `@capacitor/status-bar`
- `@capacitor/splash-screen`
- `@capacitor/push-notifications`
- `@capacitor/filesystem`
- `@capacitor/share`
- `@capacitor/preferences`
Potential later:
- Biometric auth plugin
- Camera plugin
- Background task/upload plugin if needed
## Build Targets
```text
apps/mobile/ shared React UI
apps/mobile/android/ Capacitor Android project
apps/mobile/dist/ web build consumed by Capacitor and PWA
```
Commands later:
```bash
pnpm mobile:dev # browser dev server
pnpm mobile:build # web build
pnpm android:sync # capacitor sync
pnpm android:apk # debug/release APK
```
## App Package Structure
```text
apps/mobile/
capacitor.config.ts
android/ # generated Capacitor Android project
src/
app/
App.tsx
router.tsx
providers.tsx
native.ts # Capacitor runtime helpers
screens/
AskScreen/
ActivityScreen/
@@ -65,10 +118,16 @@ apps/mobile/
notifications/
pairing/
settings/
native/
haptics.ts
push.ts
share.ts
statusBar.ts
filesystem.ts
backButton.ts
lib/
api-client.ts
realtime.ts
push.ts
audio.ts
file-utils.ts
format.ts
@@ -93,9 +152,10 @@ Bottom tabs:
- Files
- Settings
Sessions can be either:
- a sub-screen from Ask, or
- included in Activity initially.
Native back behavior:
- If a sheet/modal is open, close it.
- Else if not on Ask, go back to previous tab/screen.
- Else prompt/minimize/exit according to Android convention.
## Ask Screen Behavior
@@ -121,6 +181,7 @@ When task starts:
- Task timeline appears.
- Assistant response streams.
- Tool cards appear in chronological order.
- Subtle haptic on send, completion, error, and approval required.
## Realtime
@@ -136,35 +197,43 @@ Frontend event store should append events idempotently by event ID.
## Push Notifications
PWA flow:
1. User enables notifications in Settings.
2. App registers service worker.
3. App subscribes to PushManager.
4. Subscription sent to companion server.
5. Server sends Web Push on completion/approval/cron events.
Native Android priority:
- Use Capacitor Push Notifications / FCM where practical.
- Companion server stores device push token.
- Notifications for task completion, failure, approval required, cron completion.
Fallback if Web Push fails:
- Configure ntfy link in Settings.
Fallbacks:
- Web Push for PWA.
- ntfy/Gotify if native push is too annoying for self-hosted early builds.
Important: notification provider must be abstracted so the app can start with ntfy/Web Push and later use FCM/native without rewriting task logic.
## Voice Recording
Use MediaRecorder.
Prefer native-friendly implementation:
- First version can use browser MediaRecorder inside Capacitor WebView.
- If recording quality/lifecycle is poor, move to native audio recording plugin.
Preferred mime order:
Preferred mime order for web implementation:
- `audio/webm;codecs=opus`
- `audio/ogg;codecs=opus`
- browser default fallback
UI:
- Press/tap mic to start.
- Big recording sheet with timer/waveform.
- Big native-feeling recording sheet with timer/waveform.
- Haptic on start/stop.
- Cancel / send.
- Upload progress.
## File Upload UX
- Android file picker through `<input type=file multiple>`.
- Share Target API later for “Share to Hermes”.
Priority:
- Use standard file input first inside WebView.
- Add Capacitor Filesystem/Share integration for better Android feel.
- Later add Android share target so user can share files/text/images into Hermes Mobile from other apps.
UI:
- Preview thumbnails for images.
- File chips for archives/docs.
- Upload before task send or as part of task multipart.
@@ -172,14 +241,15 @@ UI:
## Offline/Background Behavior
- App shell should load offline.
- Draft prompt persists locally.
- Draft prompt persists locally via Capacitor Preferences/local storage.
- Running task state reloads from server after reconnect.
- Notifications tell user when background tasks finish.
- No attempt to run Hermes offline.
## Settings UX
First launch:
1. Enter companion URL or scan QR/pairing link.
1. Enter companion URL or open pairing deep link/QR.
2. Pair device.
3. Test connection.
4. Enable notifications.
@@ -193,17 +263,22 @@ Settings fields:
- Default task mode
- Upload retention display
- Hermes health
- App version/build channel
## Android Polish Checklist
## Native Polish Checklist
- `display: standalone` manifest.
- Proper app icon masks/adaptive icon assets.
- Theme color matching dark background.
- Avoid viewport resize bugs with keyboard.
- Safe-area padding.
- Disable browser pull-to-refresh where possible and add in-app refresh.
- Haptics via Vibration API where appropriate.
- Back button behavior for modals/sheets.
- Proper Android package ID, e.g. `cloud.molberg.hermesmobile`.
- Adaptive icon.
- Native splash screen.
- Status/navigation bar colors match theme.
- Edge-to-edge layout with safe-area handling.
- Keyboard does not break composer layout.
- Native back button behavior.
- Haptics on important interactions.
- Notification permission onboarding.
- Share target later.
- Deep links for pairing.
- Avoid browser pull-to-refresh in PWA fallback; app should have explicit refresh controls.
## Accessibility
@@ -211,11 +286,12 @@ Settings fields:
- Reduced motion mode.
- ARIA labels for icon buttons.
- Captions/transcript for voice notes.
- Minimum 44px tap targets.
## Future Capacitor Features
## PWA Sufficiency Summary
- Native push via FCM.
- Native share target.
- Background upload reliability.
- Local biometric unlock.
- Better notification actions: Approve/Deny from notification.
PWA is enough for a functional prototype.
Native Android is better for the product Zeb described.
Decision: build shared React app + Capacitor Android from day one, while keeping PWA fallback essentially free.