# 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//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: ``` ## 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 sendFailure(task: Task): Promise sendApproval(approval: Approval): Promise sendCron(job: CronEvent): Promise } ``` ## 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 hermes cron pause hermes cron resume ``` 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?