Files
hermes-mobile/docs/DIRECT_GATEWAY_ARCHITECTURE.md
T
2026-07-24 13:31:37 +00:00

8.9 KiB

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

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 and render tool lifecycle/progress only when tool_progress_events is advertised. Treat event payload fields defensively, retain large output outside bounded display windows, and persist only client presentation state such as expansion.
  • Do not expose artifact share/save actions until an upstream artifact handoff capability and URI/download contract are advertised; the current direct gateway contract has neither.

Unverified Assumptions

The following are useful design assumptions, not confirmed contracts:

  • Bearer authentication is accepted through an Authorization: Bearer <token> 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.