docs: initial Hermes Mobile planning scaffold
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user