Skip to content

Vanilla Hermes Chat Transport

Hermes-Relay talks to your Hermes server's own surfaces for chat — no Hermes-Relay relay plugin is ever in the chat path. By default it prefers the dashboard gateway (/api/ws, the same tui_gateway transport hermes-desktop and the TUI speak) when your Manage sign-in is ready, because that's the only Vanilla Hermes path with live thinking/reasoning as it streams. When the gateway isn't available — no dashboard auth yet, an older server, or a forced override — it falls back to the API server's SSE routes.

How It Works

Phone (WS)       → Hermes dashboard (:9119)    [preferred — gateway chat, live thinking]
Phone (HTTP/SSE) → Hermes API Server (:8642)   [fallback — sessions / runs / completions]

Both paths are vanilla upstream Hermes surfaces. The dashboard gateway /api/ws is not the Hermes-Relay relay (:8767); it's a vanilla dashboard endpoint, reached with a short-lived ticket minted from your Manage dashboard session. The Relay plugin is not the owner of standard chat. It is the encouraged extension for current upstream gaps such as Terminal/TUI, notifications, media handoff, desktop tools, Relay sessions, enhanced voice, and optional Device Control; compatible upstream surfaces take precedence as they become available.

Share into a new chat

Hermes Relay appears as a target when another Android app shares a link, text, image, or file. Choosing it opens a new conversation for your currently active profile, places shared text in the composer, and adds up to ten shared files as reviewable attachments. Mixed text-and-file shares are supported; if more than ten eligible files are shared, the app adds the first ten and tells you the rest were omitted. Multi-text shares preserve each supplied text item in source order. Nothing is sent automatically: edit, remove, reorder, or discard the draft, then tap Send when it is ready.

When it falls back, the app uses the Hermes /api/sessions REST API:

MethodEndpointPurpose
GET/api/sessionsList sessions
POST/api/sessionsCreate session
GET/api/sessions/{id}/messagesGet message history
POST/api/sessions/{id}/chat/streamStream chat (SSE)
PATCH/api/sessions/{id}Rename session
DELETE/api/sessions/{id}Delete session
GET/healthHealth check

Authentication

Current Hermes API-server deployments require a usable API_SERVER_KEY before the API server starts. The app sends that server-created value as:

Authorization: Bearer <API_SERVER_KEY>

The direct API fallback itself is optional. If you enable it, generate a strong server-side key (for example, openssl rand -hex 32; upstream requires at least 16 characters) and enter the same value in Android.

When provided, the key is stored in Android's EncryptedSharedPreferences using AES-256-GCM encryption backed by the Android Keystore.

SSE Streaming (fallback path)

On the API-server fallback, chat responses stream via Server-Sent Events with these Hermes-native event types. (On the preferred gateway path the same lifecycle arrives over the /api/ws WebSocket instead, with live reasoning.delta/thinking.delta as the model reasons — the API-server SSE surface only surfaces reasoning after the fact via tool.progress and the final run.completed messages.)

EventDescriptionKey Fields
session.createdSession initializedsession_id, run_id, title?
run.startedAgent run beginssession_id, run_id, user_message (object)
message.startedAssistant message beginssession_id, run_id, message (object with id, role)
assistant.deltaText content chunksession_id, run_id, message_id, delta
tool.progressReasoning/thinking chunksession_id, run_id, message_id, delta
tool.pendingTool queued for executionsession_id, run_id, tool_name, call_id
tool.startedTool execution startedsession_id, run_id, tool_name, call_id, preview?, args
tool.completedTool finished successfullysession_id, run_id, tool_call_id, tool_name, args, result_preview
tool.failedTool execution failedsession_id, run_id, call_id, tool_name, error
assistant.completedResponse finishedsession_id, run_id, message_id, content, completed, partial, interrupted
run.completedEntire agent run finishedsession_id, run_id, message_id, completed, partial, interrupted, api_calls?
errorError occurredmessage, error
doneStream closedsession_id, run_id, state: "final"

Why two paths?

Chat always rides vanilla upstream Hermes — never the Hermes-Relay relay plugin. The gateway /api/ws path is preferred because it's the only Vanilla Hermes surface with live reasoning streaming and full attachment support, matching what hermes-desktop and the Hermes TUI use. The API-server SSE path is the resilient fallback: it needs only the API server (no dashboard sign-in), works on older builds, and aligns with how other Hermes frontends talk to the API. The app probes both and picks the best available on each connect, so you get live thinking when your server can serve it and a working chat either way.