Files
2026-07-09 03:50:27 +00:00

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.