315 lines
7.7 KiB
Markdown
315 lines
7.7 KiB
Markdown
# Architecture
|
|
|
|
## Overview
|
|
|
|
Hermes Mobile is split into two deployable parts:
|
|
|
|
1. Mobile app
|
|
- Native Android app built with Capacitor around a shared React UI.
|
|
- PWA/web build remains available as fallback and dev target.
|
|
- 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 App |
|
|
| - Chat |
|
|
| - Tool timeline |
|
|
| - Cron UI |
|
|
| - Files |
|
|
| - Approvals |
|
|
+-------------+-------------+
|
|
|
|
|
| HTTPS REST + WebSocket/SSE + native push/Web Push fallback
|
|
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.
|
|
|
|
## Native Android Shell
|
|
|
|
Capacitor Android is part of the primary architecture, not a future contingency.
|
|
|
|
- The shared React UI builds into `apps/mobile/dist`.
|
|
- Capacitor packages that build into an Android APK.
|
|
- PWA/web access remains useful for dev, desktop, and fallback.
|
|
- Native plugins provide share target, richer push, haptics, status bar, splash screen, microphone/file improvements, and Android lifecycle hooks.
|