docs: initial Hermes Mobile planning scaffold

This commit is contained in:
Hermes Agent
2026-07-09 03:45:48 +00:00
commit 2cd4730324
14 changed files with 2139 additions and 0 deletions
+311
View File
@@ -0,0 +1,311 @@
# Architecture
## Overview
Hermes Mobile is split into two deployable parts:
1. Mobile app
- Installable PWA designed for Android.
- Talks only to the companion server.
- Does not need direct access to Hermes files or credentials.
2. Companion server
- Runs on the same Linux machine as Hermes Agent.
- Bridges mobile UI actions to Hermes Agent.
- Owns upload storage, push notifications, pairing/auth, app metadata, and realtime event fanout.
```text
+---------------------------+
| Android PWA |
| - Chat |
| - Tool timeline |
| - Cron UI |
| - Files |
| - Approvals |
+-------------+-------------+
|
| HTTPS REST + WebSocket/SSE + Web Push
v
+---------------------------+
| Hermes Companion Server |
| - Auth/pairing |
| - Task orchestrator |
| - Hermes adapters |
| - Event bus |
| - Upload store |
| - Cron wrapper |
| - Notification providers |
+------+------+-------------+
| |
| +--------------------+
| |
v v
+-------------+ +--------------+
| Hermes CLI | | Hermes files |
| Hermes API | | sessions/db |
| AIAgent | | cron jobs |
+-------------+ +--------------+
```
## Key Architectural Rule
The companion server should depend on stable Hermes surfaces first, but isolate every integration behind interfaces.
```ts
interface HermesAdapter {
health(): Promise<HermesHealth>
startTask(input: StartTaskInput): AsyncIterable<HermesEvent>
continueSession(sessionId: string, input: StartTaskInput): AsyncIterable<HermesEvent>
stopTask(taskId: string): Promise<void>
}
```
Possible implementations:
- `CliHermesAdapter`: spawns `hermes chat -q` or interactive process. Easiest baseline, weakest event detail.
- `ApiHermesAdapter`: calls Hermes API server. Good for compatibility, but generic OpenAI API hides some tool events.
- `PythonHermesAdapter`: imports Hermes Agent modules and uses callbacks for stream/tool progress. Best long-term event fidelity.
- `GatewayHermesAdapter`: uses existing gateway/session machinery if exposed.
## Companion Server Modules
```text
companion/
src/
app.ts # server bootstrap
config/ # env/yaml config loading
auth/ # pairing, sessions, tokens, passkeys later
db/ # SQLite schema/migrations/repositories
events/ # event bus + SSE/WebSocket fanout
hermes/ # adapter interface + implementations
tasks/ # task lifecycle/orchestration
uploads/ # multipart upload handling + retention
notifications/ # webpush/ntfy/gotify providers
cron/ # Hermes cron wrapper
approvals/ # approval queue + Hermes callbacks later
routes/ # REST API routes
ws/ # realtime endpoints
system/ # service health, logs, install info
```
## Event Bus
Everything that happens in the companion becomes an event.
Core event shape:
```ts
type CompanionEvent = {
id: string
type: string
taskId?: string
sessionId?: string
ts: string
level?: 'debug' | 'info' | 'warn' | 'error'
payload: unknown
}
```
Important event types:
```text
task.created
task.started
task.status
task.finished
task.failed
task.cancelled
assistant.delta
assistant.message
assistant.final
tool_call.started
tool_call.output
tool_call.finished
tool_call.failed
file.uploaded
file.generated
approval.required
approval.resolved
cron.job.listed
cron.job.updated
cron.job.finished
notification.sent
notification.failed
```
The mobile app subscribes by:
- WebSocket for active app foreground.
- SSE fallback.
- Push notifications when app is background/closed.
## Data Storage
### SQLite
Companion-owned metadata:
- paired devices
- auth sessions
- tasks
- task events
- uploaded files metadata
- notification subscriptions
- user settings/cache
Do not duplicate full Hermes session content unless needed for mobile indexing. Hermes session DB remains source of truth.
### Filesystem
Default paths:
```text
/var/lib/hermes-mobile/
hermes-mobile.db
uploads/
<task-id>/
generated/
cache/
logs/
```
User-mode install paths:
```text
~/.local/share/hermes-mobile/
~/.config/hermes-mobile/config.yaml
```
## API Surface
### Auth / Pairing
```http
POST /api/pair/start
POST /api/pair/confirm
POST /api/auth/login
POST /api/auth/logout
GET /api/me
```
Pairing flow:
1. Installer prints `https://host/pair?code=123-456`.
2. User opens on phone.
3. Server binds device and issues token.
4. Future sessions use secure cookie or bearer token.
### Tasks
```http
POST /api/tasks
GET /api/tasks
GET /api/tasks/:id
POST /api/tasks/:id/stop
GET /api/tasks/:id/events
WS /api/tasks/:id/stream
```
### Uploads
```http
POST /api/uploads
GET /api/files
GET /api/files/:id/download
DELETE /api/files/:id
```
### Sessions
```http
GET /api/sessions
GET /api/sessions/:id
POST /api/sessions/:id/continue
PATCH /api/sessions/:id
```
### Cron
```http
GET /api/cron/jobs
POST /api/cron/jobs/:id/run
POST /api/cron/jobs/:id/pause
POST /api/cron/jobs/:id/resume
DELETE /api/cron/jobs/:id
```
### System
```http
GET /api/health
GET /api/hermes/health
POST /api/hermes/test
GET /api/logs
```
## Hermes Integration Notes
Existing useful surfaces observed:
- Hermes API server exposes `/v1/chat/completions`, `/v1/responses`, `/v1/models`, `/health`.
- `AIAgent` supports `stream_delta_callback` and `tool_progress_callback` constructor params.
- Cron jobs are manageable through Hermes CLI/tooling and stored under Hermes home.
- Gateway platforms already handle STT/media patterns, but mobile should not depend on Telegram.
Long-term ideal:
- Add/consume a Hermes-native event stream from AIAgent that emits structured tool events.
- Companion server can either import Hermes modules or call a local IPC endpoint.
## Security Model
Default deployments:
1. LAN/Tailscale only, simple pairing token.
2. Public HTTPS, pairing token + device token + optional passkey.
Security requirements:
- No unauthenticated access to prompt endpoints.
- Upload size limits.
- File paths normalized; no arbitrary file read from upload endpoints.
- CSRF protection if cookie auth used.
- Audit log for approvals.
- Secrets remain in Hermes config/vault, not in mobile app.
## Notification Architecture
Provider interface:
```ts
interface NotificationProvider {
send(device: Device, message: NotificationMessage): Promise<void>
test(device: Device): Promise<void>
}
```
Providers:
- `WebPushProvider`
- `NtfyProvider`
- `GotifyProvider`
- `NoopProvider`
## Deployment Modes
### User mode
- Runs as current user.
- Uses `~/.config/hermes-mobile` and `~/.local/share/hermes-mobile`.
- Good for dev/single-user boxes.
### System mode
- Creates `hermes-mobile` system user or runs under Hermes user.
- Uses `/etc/hermes-mobile` and `/var/lib/hermes-mobile`.
- systemd service.
- Better production posture.
## Future Native Wrapper
If Android PWA is insufficient:
- Add Capacitor app under `apps/android-shell`.
- Reuse same web app.
- Gain native share target, richer push, microphone/file APIs.
+254
View File
@@ -0,0 +1,254 @@
# Companion Server Plan
## Purpose
The companion server is the local service installed beside Hermes Agent. It turns Hermes into a phone-friendly app backend without forcing Hermes core to become a mobile backend.
Responsibilities:
- Authenticate/pair phones
- Accept prompts, voice recordings, and files
- Start/continue Hermes tasks
- Stream Hermes activity to the app
- Store app metadata
- Send push notifications
- Expose cron/job/session/file APIs
- Provide health checks and install/update status
## Runtime
Preferred MVP runtime: Node.js + TypeScript.
Reasons:
- Great fit for HTTP/WebSocket/SSE/file uploads.
- Easy bundling for one-liner installs.
- PM2/systemd deployment is straightforward in Zeb's environment.
- Frontend and backend can share TypeScript event schemas.
Potential framework:
- Fastify: mature, fast, good plugins.
- Hono: simple, edge-like API, also good.
Initial pick: Fastify unless we want ultra-minimal.
## Config
Config locations:
System mode:
```text
/etc/hermes-mobile/config.yaml
/var/lib/hermes-mobile/
```
User mode:
```text
~/.config/hermes-mobile/config.yaml
~/.local/share/hermes-mobile/
```
Example:
```yaml
server:
host: 0.0.0.0
port: 8787
public_url: https://hermes-mobile.molberg.cloud
auth:
pairing_enabled: true
token_ttl_days: 90
passkeys_enabled: false
hermes:
home: /root/.hermes
mode: python # python | api | cli
cli_bin: /root/.local/bin/hermes
api_base_url: http://127.0.0.1:18793/v1
api_key: ""
storage:
data_dir: /var/lib/hermes-mobile
max_upload_mb: 512
retention_days: 30
notifications:
provider: webpush # webpush | ntfy | gotify | none
ntfy_url: https://ntfy.example.com/hermes
```
## Hermes Adapter Strategy
### Phase 1: CLI/API hybrid
- Use Hermes CLI for health tests and simple prompts.
- Use Hermes API server if available for OpenAI-compatible chat.
- Parse coarse progress where possible.
Pros:
- Requires few/no Hermes changes.
- Easy to prove app UX.
Cons:
- Tool-call visibility limited.
### Phase 2: Direct Python adapter
Run a Python worker process that imports Hermes `AIAgent` and communicates with Node over stdio or local socket.
Benefits:
- Can pass `stream_delta_callback` and `tool_progress_callback`.
- More structured event stream.
- Better session control.
Potential shape:
```text
Node companion <-- JSON lines --> Python hermes_worker.py <-- imports --> AIAgent
```
Worker commands:
- `health`
- `start_task`
- `continue_session`
- `cancel_task`
- `list_sessions`
- `cron_action`
Worker emits events:
- `assistant.delta`
- `tool_call.started`
- `tool_call.output`
- `tool_call.finished`
- `assistant.final`
### Phase 3: Hermes-native plugin/API
If Hermes Agent grows a stable event API, switch adapter implementation without rewriting app/server.
## Task Lifecycle
```text
created -> queued -> running -> finished
-> failed
-> cancelled
-> waiting_approval
```
Task record:
```ts
type Task = {
id: string
sessionId?: string
title?: string
status: TaskStatus
inputText: string
attachmentIds: string[]
createdAt: string
startedAt?: string
finishedAt?: string
error?: string
}
```
## Upload Handling
Use multipart upload endpoint.
Pipeline:
1. Validate file count/size/type.
2. Store under `uploads/<task-id-or-upload-id>/original-name`.
3. Record metadata in SQLite.
4. Include absolute file paths in Hermes prompt.
Prompt augmentation example:
```text
The user uploaded these files:
- screenshot.png: /var/lib/hermes-mobile/uploads/abc/screenshot.png (image/png, 320 KB)
- source.zip: /var/lib/hermes-mobile/uploads/abc/source.zip (application/zip, 12 MB)
User prompt:
<actual user prompt>
```
## Voice Handling
MVP options:
1. Client records `.webm`/`.ogg`, server stores it, then sends file path to Hermes with instruction to transcribe/analyze.
2. Server transcribes with local faster-whisper and sends text prompt.
Recommended MVP:
- Server-side transcription using local faster-whisper if available.
- Fallback: pass audio file to Hermes as attachment.
## Notifications
Events that trigger notifications:
- task completed after app backgrounded
- task failed
- approval required
- cron job finished/failed
Use provider abstraction:
```ts
interface NotificationProvider {
sendCompletion(task: Task): Promise<void>
sendFailure(task: Task): Promise<void>
sendApproval(approval: Approval): Promise<void>
sendCron(job: CronEvent): Promise<void>
}
```
## Pairing/Auth
MVP pairing:
1. Installer/server logs one-time code.
2. Phone opens `/pair` and enters code or uses link.
3. Server stores device and creates token.
4. Token stored in secure-ish PWA storage. Later use passkeys.
For public exposure, add:
- Rate limiting
- Token rotation
- Session revoke UI
- Optional Tailscale-only mode
## Cron Integration
Initial implementation can shell out to Hermes CLI:
```bash
hermes cron list --json
hermes cron run <id>
hermes cron pause <id>
hermes cron resume <id>
```
If CLI JSON is not available, import cron modules from Hermes Python or parse job files carefully.
## System Health
Health endpoint should check:
- companion server up
- DB writable
- upload dir writable
- Hermes CLI exists
- Hermes config exists
- Hermes API server reachable if configured
- Python worker reachable if configured
- notification provider configured
## Logging
- Structured JSON logs for service.
- Human-readable recent logs in UI.
- Do not log secrets, bearer tokens, or full uploaded file content.
## Open Questions
- Should companion run as same user as Hermes Agent for direct module/file access?
- Should public access be Cloudflare Access/Tailscale-first instead of app auth-first?
- How much Hermes core should be extended for better event streaming?
+222
View File
@@ -0,0 +1,222 @@
# Design System
## Visual Direction
Target: visually inspired by `happy.engineering` and the Happy app: polished, playful, soft, modern, high-motion, emotionally warm, and app-like.
Not a terminal dashboard. Not a generic ChatGPT clone. It should feel like a friendly command center for a personal agent.
## Keywords
- Native Android feel
- Playful but competent
- Soft cards
- Friendly gradients
- Rounded app surfaces
- Large touch targets
- Motion-rich microinteractions
- Calm dark mode
- “Agent is alive” status cues
## Initial Theme Direction
Because Zeb likes both stark terminal aesthetics and polished UIs, Hermes Mobile should combine:
- Happy-style colorful/soft app surfaces
- Hermes identity through icons, agent activity, and subtle terminal/tool-call details
- Dark-first interface for phone use
- Optional light mode later
## Color Palette Draft
```text
Background: #080A0F
Surface: #10141D
Elevated surface: #171D29
Card border: rgba(255,255,255,0.08)
Text primary: #F7F8FC
Text secondary: #AAB2C5
Muted: #687085
Hermes gold: #F2C14E
Happy blue: #6EA8FF
Happy purple: #A78BFA
Happy green: #63E6BE
Danger coral: #FF6B6B
Warning amber: #FFD166
```
Gradients:
```css
--gradient-orb: radial-gradient(circle at 30% 20%, #6EA8FF 0%, #A78BFA 45%, #080A0F 100%);
--gradient-action: linear-gradient(135deg, #6EA8FF, #A78BFA, #63E6BE);
--gradient-hermes: linear-gradient(135deg, #F2C14E, #FF8A65);
```
## Typography
Primary UI:
- Inter, Geist, or system Android sans.
Mono/details:
- JetBrains Mono for tool outputs, command snippets, paths, logs.
Type scale:
- Screen title: 28-34px, 700
- Section title: 18-20px, 650
- Body: 15-16px
- Metadata: 12-13px
- Tool output: 12-13px mono
## Layout
### Mobile shell
- Full-screen app layout.
- Safe-area aware.
- Bottom navigation with 4-5 tabs:
- Ask
- Activity
- Cron
- Files
- Settings
### Ask screen
```text
┌─────────────────────────┐
│ Hermes status orb │
│ │
│ Recent / current task │
│ ┌───────────────────┐ │
│ │ assistant answer │ │
│ └───────────────────┘ │
│ ┌───────────────────┐ │
│ │ tool timeline │ │
│ └───────────────────┘ │
│ │
│ [ + ] [ hold voice ] │
│ [ prompt input ↑ ] │
└─────────────────────────┘
```
Input should be thumb-first:
- Attachment left
- Voice pill / mic
- Send button right
- Input grows to 4-6 lines max
## Components
### Agent Status Orb
A small animated orb/avatar indicating:
- idle
- thinking
- using tools
- waiting for approval
- done
- error
This gives the app life without pretending to be a person.
### Tool Card
States:
- queued
- running
- success
- failed
- cancelled
Collapsed view:
```text
[terminal icon] terminal • 2.4s • success
npm test
```
Expanded view:
- Arguments summary
- Output preview
- Copy button
- Open file if applicable
- Error highlighting
### Timeline
Vertical event feed with icons and subtle connecting line.
Events:
- Prompt received
- Tool started
- Tool output
- File generated
- Notification sent
- Final answer
### Approval Card
Should feel serious but not scary.
```text
Approval required
Hermes wants to run:
rm -rf /tmp/build-cache
Risk: destructive file operation
[ Deny ] [ Approve once ]
```
### Cron Job Card
```text
Homelab health check
Every day 09:00
Last run: success · 2h ago
[Run now] [Pause]
```
### Upload Tray
Shows selected files before sending:
- thumbnail for images
- file icon for zip/pdf/log
- remove button
- total size
## Motion
Use motion sparingly but meaningfully:
- status orb breathing while thinking
- tool card expands smoothly
- file upload progress liquid/soft bar
- send button morphs to spinner
- completion haptic-like visual pulse
Prefer CSS transitions and Framer Motion if bundle size acceptable.
## Android-native Feeling
- Installable PWA manifest with proper icons.
- Standalone display mode.
- No browser chrome when installed.
- Bottom nav like native Material apps.
- Pull-to-refresh disabled; in-app refresh buttons where needed.
- Back gesture should close panels before navigating away.
- Use Android share target later so user can share files/text to Hermes.
## Accessibility
- Minimum 44px tap targets.
- Color is not the only status indicator.
- Reduced motion support.
- Good contrast in dark mode.
- Voice actions have text alternatives.
## Design TODO
- Capture screenshots/references from happy.engineering and Happy app.
- Build a visual moodboard.
- Design first mockups for Ask, Tool Timeline, Cron, Settings.
- Decide exact logo/avatar direction.
+224
View File
@@ -0,0 +1,224 @@
# Install Strategy
## Goal
A one-liner installer that sets up the companion server beside an existing Hermes Agent install.
Target UX:
```bash
curl -fsSL https://hermes-mobile.molberg.cloud/install.sh | bash
```
or from Gitea release/raw if accessible without auth:
```bash
curl -fsSL https://git.molberg.cloud/bonzi/hermes-mobile/raw/branch/main/install.sh | bash
```
Because Zeb's Gitea raw URLs may require auth, release assets or a mirrored static install URL are safer for the public one-liner.
## Installer Responsibilities
1. Detect OS/package manager.
2. Detect Hermes Agent:
- `command -v hermes`
- `~/.hermes/config.yaml`
- optional `HERMES_HOME`
3. Check Node.js version or install bundled binary/runtime.
4. Download latest Hermes Mobile companion release.
5. Create config.
6. Create data directories.
7. Install systemd service.
8. Start service.
9. Print pairing URL and one-time code.
## Installation Modes
### System mode (default for servers)
Paths:
```text
/opt/hermes-mobile/ app bundle
/etc/hermes-mobile/config.yaml config
/var/lib/hermes-mobile/ DB/uploads/cache
/var/log/hermes-mobile/ logs if not journald-only
```
Service:
```text
hermes-mobile-companion.service
```
Run user:
- Option A: current user/root if Hermes is root-installed.
- Option B: `hermes-mobile` user with group/read permissions to Hermes paths.
For Zeb's box, same user/root is simplest initially because Hermes files live under `/root/.hermes`.
### User mode
```bash
curl ... | bash -s -- --user
```
Paths:
```text
~/.local/opt/hermes-mobile/
~/.config/hermes-mobile/config.yaml
~/.local/share/hermes-mobile/
~/.config/systemd/user/hermes-mobile-companion.service
```
## Service Unit Draft
```ini
[Unit]
Description=Hermes Mobile Companion Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/hermes-mobile
Environment=NODE_ENV=production
Environment=HERMES_MOBILE_CONFIG=/etc/hermes-mobile/config.yaml
ExecStart=/usr/bin/node /opt/hermes-mobile/server/index.js
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
```
## Config Generation
Installer should write:
```yaml
server:
host: 0.0.0.0
port: 8787
public_url: ""
hermes:
home: /root/.hermes
cli_bin: /root/.local/bin/hermes
mode: python
api_base_url: http://127.0.0.1:18793/v1
storage:
data_dir: /var/lib/hermes-mobile
max_upload_mb: 512
auth:
pairing_enabled: true
notifications:
provider: webpush
```
## Pairing Output
After start:
```text
Hermes Mobile installed.
Open this on your phone:
http://SERVER-IP:8787/pair?code=123-456
Pairing code:
123-456
Service:
systemctl status hermes-mobile-companion
Logs:
journalctl -u hermes-mobile-companion -f
```
## Update
```bash
curl -fsSL https://hermes-mobile.molberg.cloud/install.sh | bash -s -- --update
```
Should:
- Download latest release.
- Preserve config and data.
- Restart service.
- Run DB migrations.
## Uninstall
```bash
curl -fsSL https://hermes-mobile.molberg.cloud/install.sh | bash -s -- --uninstall
```
Should ask/flag whether to keep data:
- `--keep-data`
- `--purge`
## Release Layout
Build artifact:
```text
hermes-mobile-linux-x64.tar.gz
server/
index.js
package.json
node_modules/ or bundled single executable
public/
PWA assets
scripts/
hermes_worker.py
migrations/
```
Better later:
- single static binary via Bun/Node SEA if stable enough.
- Docker image optional but not the primary install path.
## One-liner Safety
Installer should:
- Show what it will do.
- Avoid deleting data unless explicitly asked.
- Not overwrite existing config without backup.
- Use `set -euo pipefail`.
- Log to temp file.
- Verify download checksum if release metadata supports it.
## Development Install
From cloned repo:
```bash
pnpm install
pnpm dev
```
Companion dev server:
```bash
pnpm --filter companion dev
```
Mobile dev server:
```bash
pnpm --filter mobile dev --host 0.0.0.0
```
## Future Cloudflare/Tailscale
Expose options:
- Tailscale only: bind to `100.x` IP or localhost behind `tailscale serve`.
- Cloudflare Tunnel: companion prints local port and expected reverse proxy config.
- Nginx/Caddy snippets generated by installer.
+221
View File
@@ -0,0 +1,221 @@
# Mobile App Plan
## App Type
Start as a PWA optimized for Android Chrome.
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.
Potential later native shell:
- Capacitor Android for native share target, richer notifications, and better file/mic APIs.
## Frontend Stack
Recommended:
- Vite + React + TypeScript
- Tailwind CSS
- TanStack Query for server data
- Zustand for local UI/session state
- Framer Motion for motion where useful
- Workbox or Vite PWA plugin
- Zod for API schema validation
Alternative:
- Next.js if SSR/server components become useful, but for a companion-served app Vite is simpler.
## App Package Structure
```text
apps/mobile/
src/
app/
App.tsx
router.tsx
providers.tsx
screens/
AskScreen/
ActivityScreen/
SessionsScreen/
CronScreen/
FilesScreen/
SettingsScreen/
components/
agent-status-orb/
composer/
tool-card/
event-timeline/
upload-tray/
voice-recorder/
cron-job-card/
approval-card/
bottom-nav/
app-shell/
features/
tasks/
sessions/
cron/
files/
approvals/
notifications/
pairing/
settings/
lib/
api-client.ts
realtime.ts
push.ts
audio.ts
file-utils.ts
format.ts
styles/
globals.css
tokens.css
assets/
icons/
splash/
main.tsx
public/
manifest.webmanifest
service-worker.ts
```
## Navigation
Bottom tabs:
- Ask
- Activity
- Cron
- Files
- Settings
Sessions can be either:
- a sub-screen from Ask, or
- included in Activity initially.
## Ask Screen Behavior
States:
- idle
- composing
- uploading
- sending
- running
- waiting_approval
- finished
- failed
Composer:
- Text input
- Attach file button
- Hold/tap voice recording button
- Send button
- Optional mode chips: New / Continue / Background
When task starts:
- Input collapses to bottom.
- Task timeline appears.
- Assistant response streams.
- Tool cards appear in chronological order.
## Realtime
Use WebSocket first:
- `/api/realtime?token=...`
- Subscribe to task/session events.
Fallback:
- SSE `/api/tasks/:id/events/stream`
- Polling last resort.
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.
Fallback if Web Push fails:
- Configure ntfy link in Settings.
## Voice Recording
Use MediaRecorder.
Preferred mime order:
- `audio/webm;codecs=opus`
- `audio/ogg;codecs=opus`
- browser default fallback
UI:
- Press/tap mic to start.
- Big recording sheet with timer/waveform.
- Cancel / send.
- Upload progress.
## File Upload UX
- Android file picker through `<input type=file multiple>`.
- Share Target API later for “Share to Hermes”.
- Preview thumbnails for images.
- File chips for archives/docs.
- Upload before task send or as part of task multipart.
## Offline/Background Behavior
- App shell should load offline.
- Draft prompt persists locally.
- Running task state reloads from server after reconnect.
- No attempt to run Hermes offline.
## Settings UX
First launch:
1. Enter companion URL or scan QR/pairing link.
2. Pair device.
3. Test connection.
4. Enable notifications.
5. Land on Ask.
Settings fields:
- Companion URL
- Device name
- Notification status/test
- Theme
- Default task mode
- Upload retention display
- Hermes health
## Android 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.
## Accessibility
- Visible focus states.
- Reduced motion mode.
- ARIA labels for icon buttons.
- Captions/transcript for voice notes.
## Future Capacitor Features
- Native push via FCM.
- Native share target.
- Background upload reliability.
- Local biometric unlock.
- Better notification actions: Approve/Deny from notification.
+250
View File
@@ -0,0 +1,250 @@
# Product Plan
## Working Name
Hermes Mobile
## One-line Pitch
A private Android-first app for talking to Hermes Agent with voice, files, live tool calls, approvals, cron controls, and completion notifications.
## Target User
Primary: Zeb / homelab power user who already runs Hermes Agent on a Linux machine and wants a better phone interface than Telegram.
Secondary later:
- Developers running Hermes locally/remotely
- Homelab admins
- People who want an agent command center rather than a chatbot
## Non-goals
- Not a generic OpenAI chat frontend.
- Not a multi-provider model playground.
- Not a public SaaS.
- Not a replacement for Hermes Agent internals.
- Not a Matrix/Discord/Telegram clone.
## Design Principles
1. Agent-first, not chat-first
- The UI should show what Hermes is doing, not just the final response.
- Tool calls are first-class objects.
2. Phone-native ergonomics
- Thumb-reachable controls.
- Large tap targets.
- Voice and upload actions always nearby.
- Background task status survives app close/reopen.
3. Private by default
- Self-hosted companion server.
- Local uploads.
- Optional LAN/Tailscale-only mode.
- No third-party notification requirement unless chosen.
4. Modular integrations
- Hermes CLI bridge now.
- Hermes API bridge where useful.
- Direct Python/event bridge later.
- Notification providers swappable.
5. Install should feel boring
- One command.
- Clear service status.
- Easy update/uninstall.
## Core Screens
### 1. Home / Ask
Purpose: send a prompt fast.
Features:
- Text box with multiline support
- Hold-to-record voice note
- Attach button
- Model/session selector compact chip
- “New task” vs “continue session” toggle
- Streaming answer
- Activity timeline under/alongside answer
- Completion toast/push
### 2. Activity
Purpose: see active and recent agent runs.
Features:
- Running tasks
- Tool-call cards
- Logs/output previews
- Generated files
- Error states
- Stop/cancel if supported
### 3. Sessions
Purpose: browse/resume history.
Features:
- Recent conversations
- Search
- Rename/pin/archive
- Session metadata: platform, started, last active, tool count, attachments
### 4. Cron
Purpose: manage scheduled Hermes tasks from phone.
Features:
- Job list grouped by active/paused/completed
- Run now
- Pause/resume/remove
- Edit prompt/schedule later
- Last output viewer
- Delivery target setting: in-app inbox, push, Matrix/Telegram/etc.
### 5. Files
Purpose: manage uploaded/generated artifacts.
Features:
- Upload inbox
- Generated media/files from responses
- Download/share
- Link file into a new prompt
- Retention controls later
### 6. Approvals
Purpose: approve dangerous actions safely.
Features:
- Pending approvals queue
- Command/action preview
- Risk label
- Approve once / deny
- Expiry countdown
- Audit log
### 7. Settings
Purpose: connect to companion server and configure app.
Features:
- Server URL
- Pairing code / passkey login
- Notification test
- Theme
- Hermes health
- Storage/retention
- STT/TTS preferences
## Feature Details
### Text Prompting
Modes:
- Quick ask: starts new task/session.
- Continue: appends to selected session.
- Background task: app can be closed, push when finished.
### Voice Notes
MVP flow:
1. Browser MediaRecorder captures audio.
2. Upload audio file to companion.
3. Companion either:
- passes audio path to Hermes gateway/STT path, or
- transcribes with configured local Whisper/faster-whisper, then sends text prompt.
4. UI shows transcript for confirmation if desired.
Later:
- Voice-to-voice replies using Hermes TTS.
- Streaming partial transcript.
### File Uploads
Supported MVP:
- png/jpg/webp/gif
- zip/tar/gz
- pdf
- txt/log/md/json/csv
- arbitrary binary as attachment
Prompt format to Hermes:
- Store file locally in companion upload store.
- Send prompt with absolute paths and metadata.
- Example: `User uploaded files: /var/lib/hermes-mobile/uploads/.../archive.zip`
### Tool Calls
Event model:
- `tool_call.started`
- `tool_call.delta`
- `tool_call.finished`
- `tool_call.failed`
Tool cards show:
- Icon/name
- Arguments summary
- Status
- Duration
- Expandable result
- Copy/open file actions where relevant
### Notifications
MVP notification events:
- task finished
- task failed
- approval required
- cron job completed/failed
Providers:
- Web Push for installed PWA
- ntfy fallback
- Gotify fallback
- Home Assistant persistent notification optional
### Cron Triggers
The app should not reimplement Hermes cron. It should wrap Hermes cronjob functions/CLI:
- list jobs
- run job
- pause/resume/remove
- create/edit later
### “Prompting itself” / Hermes test harness
Because Hermes Mobile runs next to Hermes Agent, the companion can test connectivity by sending a harmless prompt through:
- Hermes CLI: `hermes chat -q "ping"`
- API server: `/v1/chat/completions`
- Direct Python bridge later
The Settings health page should include a `Test Hermes` button.
## MVP Acceptance Criteria
- Install companion server on same Linux machine as Hermes.
- Open mobile PWA on Android, pair to companion.
- Send text prompt to Hermes and receive answer.
- Upload a PNG or ZIP and include it in prompt context.
- Record a voice note and turn it into a prompt.
- See at least coarse tool activity while Hermes runs.
- Receive push/ntfy notification when task completes.
- View cron jobs and trigger one manually.
## Risks
1. Hermes API server may not expose enough event detail.
- Mitigation: start with CLI/direct Python bridge and add event callbacks.
2. PWA push notification quirks.
- Mitigation: support ntfy/Gotify fallback.
3. Mobile browser audio quirks.
- Mitigation: test Android Chrome first; Capacitor later if needed.
4. Tool-call streaming requires Hermes integration changes.
- Mitigation: companion adapter interface; use available callbacks in AIAgent where possible.
+132
View File
@@ -0,0 +1,132 @@
# Roadmap
## Phase 0 — Planning Scaffold
Status: current.
Deliverables:
- Repo created
- Product plan
- Architecture plan
- Design direction
- Install strategy
- Project structure
## Phase 1 — Skeleton
Goal: empty but runnable monorepo.
Deliverables:
- pnpm workspace
- `apps/mobile` Vite React PWA
- `apps/companion` Fastify server
- shared TypeScript package for event/API schemas
- basic app shell with bottom nav
- `/api/health`
- local dev scripts
## Phase 2 — Basic Hermes Prompting
Goal: phone can send text prompt and receive final answer.
Deliverables:
- pairing/auth MVP
- Settings connect flow
- task creation endpoint
- Hermes CLI/API adapter MVP
- Ask screen sends prompt
- response display
- task history in SQLite
## Phase 3 — Realtime Activity + Tool Timeline
Goal: see Hermes work live.
Deliverables:
- event bus
- WebSocket/SSE stream
- tool timeline UI
- Python worker adapter using AIAgent callbacks if needed
- coarse/fine tool event mapping
## Phase 4 — Uploads + Voice
Goal: prompt with files and voice notes.
Deliverables:
- multipart upload endpoint
- upload tray UI
- image/archive/pdf metadata
- voice recorder UI
- local STT or Hermes STT bridge
- attach files to task prompt
## Phase 5 — Notifications
Goal: close phone and get told when done.
Deliverables:
- PWA service worker
- Web Push subscription management
- notification provider abstraction
- ntfy fallback
- completion/failure/approval notifications
## Phase 6 — Cron + Approvals
Goal: mobile control plane.
Deliverables:
- cron list/run/pause/resume/remove
- cron output viewer
- approval queue UI
- companion approval API
- Hermes approval integration strategy
## Phase 7 — Installer + Release
Goal: one-liner install.
Deliverables:
- production build
- install.sh
- systemd service
- update/uninstall modes
- release artifact
- pairing URL output
## Phase 8 — Android Polish
Goal: feels native.
Deliverables:
- refined Happy-inspired UI
- animations/microinteractions
- adaptive icons/splash
- share target
- haptics
- offline shell polish
- optional Capacitor wrapper evaluation
## Phase 9 — Deep Hermes Integration
Goal: full Hermes-native experience.
Deliverables:
- structured event stream from Hermes core or stable Python adapter
- richer session browsing
- generated file detection
- background process control
- subagent visualization
- memory/skills dashboards possibly
## Open Feature Ideas
- Quick action tiles: “Check homelab”, “Run DV status”, “Start coding task”.
- Voice-to-voice mode.
- Per-task model/toolset selection.
- “Watch mode” for long-running coding tasks.
- Home Assistant widgets/actions.
- Secure notification actions: approve/deny from notification.
- Android native share target.
- QR pairing from terminal output.
+119
View File
@@ -0,0 +1,119 @@
# Testing Strategy
## Philosophy
Hermes Mobile must be tested as an app plus a local service plus a Hermes integration. Generic unit tests are not enough; the important thing is whether a phone can send work to Hermes, see activity, close the app, and get notified when done.
## Test Layers
### 1. Unit Tests
Frontend:
- event reducer/idempotency
- upload tray state
- voice recorder state machine
- API client error handling
- cron job card states
Companion:
- config loading
- auth pairing tokens
- notification provider interface
- upload path normalization
- event bus fanout
- task state transitions
### 2. Integration Tests
Companion server with fake Hermes adapter:
- create task
- stream events
- upload file + attach to task
- completion notification queued
- cron list/run mocks
Hermes adapter contract tests:
- CLI adapter health
- API adapter health
- Python worker JSONL protocol
### 3. End-to-End Tests
Use Playwright against local dev server.
Scenarios:
- first-time pairing
- send text prompt
- upload PNG and send prompt
- record/upload fake audio blob
- watch tool timeline update
- cron run button
- notification permission flow mocked
### 4. Real Hermes Smoke Tests
On a machine with Hermes installed:
```bash
hermes chat -q "Reply with exactly: hermes-mobile-ok"
```
Companion health test should do the equivalent and verify response.
More advanced smoke:
- Ask Hermes to run a harmless terminal command: `pwd`.
- Verify a tool-call event appears.
- Upload a small text file and ask Hermes to summarize it.
## Manual Android QA
Test on Android Chrome installed PWA:
- Install app to home screen.
- Launch standalone mode.
- Keyboard does not break composer layout.
- Back button closes sheets/modals first.
- Voice recording works.
- File picker works for image/zip/pdf.
- Push notification arrives after app is backgrounded.
- App reconnects to running task after being killed/reopened.
## Compatibility Targets
- Android Chrome latest
- Android Firefox optional
- Desktop Chrome for dev
- iOS Safari later, not MVP priority
## Observability for Testing
Companion should expose:
```http
GET /api/health
GET /api/debug/events/recent
GET /api/debug/config/redacted
POST /api/hermes/test
POST /api/notifications/test
```
Only expose debug endpoints in dev mode or authenticated admin mode.
## CI Plan
Later:
- pnpm lint
- pnpm typecheck
- pnpm test
- pnpm e2e with fake adapter
- build release artifact
## Dogfooding Plan
The app should be used to prompt Hermes about its own repo.
Example dogfood tasks:
- “Run the test suite for Hermes Mobile and summarize failures.”
- “Inspect the companion logs and fix the upload bug.”
- “Create a cron job that reminds me if companion is down.”
This is important because Hermes is both the target agent and the tool used to build the app.