# Hermes Mobile Direct Gateway Architecture Hermes Mobile is pivoting to a native Android client that talks directly to a remote upstream Hermes Agent gateway/API server. The `apps/companion` TypeScript server is legacy compatibility code and must not be required by Android or future releases. ## Architecture ```text Android app Kotlin/Compose UI connection/auth storage transport DTOs domain repositories | | HTTPS, bearer token when configured v Upstream Hermes Agent gateway/API server auth/session authority chat/completion authority streaming/tool/artifact authority provider credentials and Hermes runtime ``` The Android app remains a thin client. It may store server profiles, non-provider UI preferences, selected session IDs, and Android-secured bearer tokens. It must not embed provider credentials, clone Hermes backend behavior, or make the legacy companion server part of the release path. ## Documented Upstream Surface The current repository/context documents these upstream Hermes API-server endpoints: | Endpoint | Status | Mobile contract | | --- | --- | --- | | `GET /health` | Documented | Primary reachability and compatibility probe. Response shape beyond a successful JSON response is treated as server-specific. | | `GET /v1/models` | Documented | Authenticated compatibility probe for bearer-token connections and future model picker source. | | `GET /v1/capabilities` | Documented | Capability negotiation source. Current upstream behavior advertises endpoints as `{method, path}` objects and feature support as booleans. | | `POST /v1/chat/completions` | Documented | Baseline OpenAI-compatible chat path. Mobile must assume this may not expose Hermes session IDs or structured tool events. | | `POST /v1/responses` | Documented | Preferred future request/streaming path if upstream exposes richer response events. Exact Hermes event mapping is not yet verified. | | `/api/sessions/*` | Documented and capability-advertised | List/create/get/update/delete/messages/fork/chat/chat-stream routes exist, but mobile must use only the exact advertised method/path object and must not infer search or other routes. | | `POST /api/sessions/{session_id}/chat/stream` | Documented and capability-advertised | SSE session turn. Core mobile support begins with `message.started`, `assistant.delta`, authoritative `assistant.completed`, `error`, and `done`; tool events remain gated by `tool_progress_events`. | Any route not listed here must be labeled provisional until checked against official Hermes Agent docs or a running gateway. Session search remains explicitly unverified and unmapped. ## Direct stream lease contract - Parse `session_chat_streaming`, `tool_progress_events`, and `endpoints.session_chat_stream` from `GET /v1/capabilities`. - Require the advertised session stream endpoint to be `POST`, use an absolute path containing `{session_id}`, and send the documented JSON `input` field. - Bind the request URL, route generation, session ID, endpoint path, and structured-event gate into one immutable lease before the HTTP call starts. - Execute that prebuilt request through OkHttp without consulting route selection again until the call ends. - Never apply an SSE event whose `session_id` differs from the bound lease. A later Local/Remote re-evaluation applies only to a later request. - Append `assistant.delta` text deterministically, then replace it with the authoritative `assistant.completed.content` response when present. - Report HTTP, I/O, or malformed-SSE failure only against the route/session lease that owned the failed call; an upstream `error` event fails the session without invalidating the route. - Decode tool lifecycle/progress only when `tool_progress_events` is advertised; B4 does not render or persist those structured payloads. ## Unverified Assumptions The following are useful design assumptions, not confirmed contracts: - Bearer authentication is accepted through an `Authorization: Bearer ` header on `/v1/*`. - `/health` returns a stable `status` field. - `/v1/responses` can provide enough streaming metadata to preserve Hermes sessions, artifacts, cancellation, and reconnect state. - Hermes session search has a stable direct HTTP endpoint. - Tool result and artifact listing/download have stable direct HTTP endpoints. - Cancellation has a stable direct HTTP endpoint. - Error payloads consistently include `message` or `error`. Android contracts may model these needs, but implementation must keep them capability-gated until verified. ## Compatibility Policy - Direct gateway routes are the default target for all new Android transport work. - Legacy companion routes such as `/api/health`, `/api/auth/validate`, `/api/chat`, `/api/files/*`, and `/api/terminal/*` are temporary compatibility only. - UI and domain terminology should say "gateway", "server", or "upstream Hermes" unless explicitly describing legacy companion behavior. - The transport/domain model exposes direct gateway capabilities first. `legacyCompanionAdapter` exists only to identify old adapters during migration. - Backend behavior belongs upstream in Hermes Agent. Hermes Mobile may add client adapters and mappers, not server-side replacements. ## Local-first gateway routing A server profile can contain two URLs for the **same Hermes gateway identity**: - **Local URL** — preferred when the phone can safely reach the gateway on the home/LAN (for example, `https://hermes.home.arpa`). - **Remote URL** — fallback when local reachability is unavailable (for example, a configured public HTTPS hostname). The client must choose automatically per connection attempt: 1. If a local URL is configured, probe its documented `GET /health` endpoint using a short, bounded timeout. 2. Use the local URL when the probe succeeds and the gateway identity/auth contract is compatible. 3. Otherwise immediately use the configured remote URL; never leave chat blocked waiting for LAN discovery. 4. Re-evaluate on app foreground, explicit reconnect, connectivity changes, and after a failed active request. Do not switch a request mid-stream. 5. Show the active route (`Local` or `Remote`) in connection diagnostics, but do not expose bearer tokens or internal host details in message content/logs. Security and reliability rules: - Local and remote URLs are explicit user configuration, not guessed IP ranges or silently discovered devices in the MVP. - Both routes must use HTTPS by default and must be treated as the same intended gateway only after an authenticated compatibility check. The app must not silently send a bearer token to an arbitrary captive portal or unrelated LAN host. - Remote is a fallback, not a duplicate profile. User preferences, selected session state, and credentials stay associated with one logical gateway profile. - A later milestone may add opt-in mDNS/QR setup, certificate pinning/identity binding, and richer connectivity observation only after direct-gateway basics are verified. - The current upstream identity-binding limitation and the stronger contract needed are tracked in `docs/BLOCKERS.md`. ## Android Contract Milestones 1. Auth and connection: validate local + remote URLs, store bearer tokens securely, probe `GET /health`, use `GET /v1/models` as the first authenticated check, and make local-first fallback observable/retryable. 2. Sessions: keep repository interfaces for list/create/select/continue, but mark route mapping provisional until upstream session docs are verified. 3. Streaming: support final response and token delta reduction now; gate structured tool/artifact/session events behind server capabilities. Keep each stream bound to its selected local or remote route. 4. Companion removal: after direct gateway chat/session/streaming works end to end, remove legacy companion UI routes and then deprecate install/docs around `apps/companion`. ## Verified Session Capability Boundary — 2026-07-24 Official upstream API server documentation defines authenticated `GET /v1/capabilities` discovery and advertises session endpoint entries including `session_list`, `session_create`, `session_get`, and `session_delete`. The Android B3 foundation therefore builds requests only from those returned endpoint strings; a missing entry leaves that operation unavailable rather than falling back to an assumed route. Source checked: `https://hermes-agent.nousresearch.com/docs/user-guide/features/api-server/` on 2026-07-24. The same official endpoint table does not document session search or a search query schema. Hermes Mobile keeps search in the repository contract and fake implementation for UI/state verification, but does not map search to HTTP until upstream publishes that contract. The exact blocker is tracked in `docs/BLOCKERS.md`.