Hermes Provider
The Hermes CLI from Nous Research as an alternative session provider — a different agent on your own key, not Claude in a different harness. How to enable it, the readiness gaps, and how it behaves against the other providers.
What it is
Omniscio can spawn Claude-Code-style sessions backed by the Hermes CLI (hermes, by Nous Research) as an alternative provider, alongside claude (the default), codex, gemini, antigravity, the Anthropic-compatible deepseek / kimi, opencode, and cursor. Hermes is a model-agnostic, tool-using coding agent you install locally; it runs on its own model + provider key (whatever you set with hermes setup), so a Hermes session is "a different agent on your own key," not Claude in a different harness.
Why it exists: a migration on-ramp. An existing Hermes user can run their own Hermes install from inside Omniscio — keeping the agent they know while moving onto Omniscio.
Migrated to ACP (2026-08-01). Hermes was previously driven as a per-turn one-shot spawn (hermes -z), which broke multi-turn memory in Hermes v0.19.0 (the -z mode stopped restoring conversation history). Hermes is now driven over the Agent Client Protocol — a kept-alive hermes acp child, the same pattern as Kimi Code and Gemini — so multi-turn memory is native and real. This was verified live: turn 1 "favorite color is teal" → "got it"; turn 2 "what color?" → "teal".
What the user sees
A Hermes session looks almost identical in the sidebar and main pane to a Claude session — same status dots, same streaming bubbles, same Ctrl+Enter to send. The differences:
- Amber "Hermes" pill in the session header (next to the title), like Codex (emerald), Cursor (indigo), Gemini (violet). Hermes is a first-class provider — it shows a badge, is a per-project default, and is switch-to-able.
- Token-by-token streaming. Omniscio drives the kept-alive
hermes acpchild over JSON-RPC/NDJSON on stdio (the shared ACP layer), so the reply appears incrementally as it generates. When the turn completes, one final push replaces the bubble with the full accumulated text. - Real stateful multi-turn. Because Hermes runs as a kept-alive ACP process, conversation memory is native — the agent remembers the full session history without Omniscio replaying prior turns as context.
- Runs on YOUR Hermes config. Omniscio passes Hermes nothing but your prompt — no model overrides, no
--modelarg — so the session uses whatever model and key you configured withhermes setup. Omniscio stores no key for Hermes. - No per-session dollar cost. Hermes emits no token/cost over ACP v1, so Omniscio shows turn counts but the Cost line is hidden / $0 for Hermes sessions. Your spend is tracked in your own provider account (the key you gave Hermes).
- Images go straight to the agent when your Hermes build can read them. On start-up Omniscio asks the running
hermes acpchild whether it accepts image prompts; if it does, an attached image is sent inline as an ACP image block. If it does not, the image is not sent and the session shows a short note saying so — describe the image in words, or switch to an engine with image support — never a silent drop. Documents are not delivered to Hermes (the compose area warns before you send). - Your project's MCP servers are handed to Hermes when its session starts, through the same shared ACP layer Gemini and Kimi Code use; remote (HTTP) servers only when the child said it supports that transport. If Hermes refuses to start with the servers, Omniscio starts it once more without them and tells you in the session.
Where to find it
How to enable
Master toggle required first. Hermes is an alternative provider — on a fresh install Hermes is already visible (the master toggle is ON by default since 2026-10-03); on a profile that last saved before that setting existed the entire Hermes setup section stays hidden in Settings → Accounts until you flip it on. Flip Settings → Accounts → Show alternative AI providers to ON and the Hermes (CLI provider) panel appears. With the master off, the per-launch provider switcher hides Hermes. Your "Allow Hermes sessions" toggle is preserved across master-toggle flips.
Two gates must both pass (getProviderSpawnReadiness enforces them in this order) — no API-key gate (Hermes holds its own credential):
- Hermes CLI binary — the
hermesbinary must be installed. Omniscio detects it (on PATH, the official Windows install dir%LOCALAPPDATA%\hermes\venv\Scripts\hermes.exe, or$HERMES_HOME\venv\Scripts) but does not install it. Install it from Nous Research's instructions, then runhermes setupto choose a model and add your provider key. Omniscio waits up to 30s and treats "present on disk = installed." If you just installed it, restart Omniscio so the running process picks up your updated PATH. - Allow Hermes sessions toggle — off by default. Same security stance as the other auto-running providers: enable only because you intend to use it. Lives in the Hermes panel as Allow Hermes sessions in any project.
Once both are green, you launch a Hermes session three ways:
- Per-project default — the Edit-Project "Default provider" radios and the "+ New Session" split-button include Hermes. New sessions in that project spawn Hermes automatically.
- Per-launch override — on a fresh (zero-message) session, the Change-provider button (the launch-config pickers on a fresh session) lets you pick Hermes before sending the first message. A not-ready provider appears disabled with an "Install…" suffix that deep-links into the relevant Settings panel.
- Programmatically — anything that creates a session with
provider: 'hermes'(recipes, the CLI control server, deep-links). The same two readiness gates apply on the backend.
How it behaves
No virtual project
Hermes has no dedicated __hermes__ sidebar entry (unlike __codex__ / __gemini__ / __antigravity__), and therefore no sentinel bypass of the "Allow Hermes sessions" toggle — the toggle always applies. You spawn Hermes inside any real project. (This matches Cursor/OpenCode; only Codex/Gemini/Anti-Gravity have virtual projects.)
Error states and fixes
Two gap codes (no key gap — Hermes uses its own credential):
| Gap | What it means | Click-to-fix lands you at… |
|---|---|---|
toggle-off |
"Allow Hermes sessions" is OFF in Settings | Settings → Accounts → Allow Hermes sessions toggle |
binary-missing |
hermes CLI not found |
Settings → Accounts → Hermes CLI panel |
If a turn fails after Hermes is found, the most common cause is Hermes not being fully set up — the failure message points you at hermes setup (pick a model + add a key). An auth failure on session creation surfaces "run hermes setup to pick a model and add a key, then try again."
If a turn is rejected because Hermes's own working memory outgrew the model's window (usually a command that printed a huge amount of output), the message says it ran out of room and that the conversation is saved. Omniscio has already replaced the overflowed hermes acp process, so your next message starts fresh on a compact copy of the conversation — usually no new session is needed. If it still runs out of room, the conversation may be too long for the model, so start a new session.
For agents
How it works under the hood
Kept-alive ACP child per session. Omniscio spawns hermes acp --accept-hooks once and keeps it alive for the session's lifetime — the same Agent Client Protocol pattern as Gemini and Kimi Code. JSON-RPC 2.0 frames flow over the child's stdio (NDJSON framing, shared AcpClient transport and acp-update-translator layer). The hermes acp child starts lazily on the first message, so creating or switching to a Hermes session is instant. On an app restart the manager re-registers and re-spawns a fresh child on the next message.
hermes acp --accept-hooks. The acp subcommand runs Hermes in its ACP server mode. --accept-hooks auto-approves headless shell hooks (no TTY in the child process) so turns don't block waiting for interactive confirmation. No --model arg is passed — Hermes runs the user's configured model from hermes setup / config.yaml; AMC must not override it.
Real stateful multi-turn. Because the ACP session is kept alive, Hermes maintains the full conversation history natively. There is no Omniscio-side history replay on every turn (the old -z mode required this workaround, and it broke in v0.19.0). This migration was the fix.
Auth stays in Hermes's own config.yaml. Omniscio spawns with a clean environment (buildCleanSpawnEnv()) — no key is injected, no ambient credential can silently hijack billing. A session/new auth failure is humanized to "run hermes setup"; Omniscio does NOT attempt an ACP authenticate call (Hermes's auth methodIds are undocumented in v1).
Permission requests — v1 auto-approve. The permission handler auto-approves all tool calls (allow). This is the same documented v1 posture as Kimi Code: acceptable for v1 because we can't yet confirm whether Hermes's ACP server even sends session/request_permission vs. auto-running tools itself. Adding the shared dangerous-path denylist net (the same one Gemini's handler uses) is a tracked hardening follow-up.
Cost tracking ($0 today). Hermes ACP v1 exposes no token/cost data, so each turn records $0 via updateSessionCost (costReporting: 'none'). numTurns is bumped per turn so the sidebar's blank-session filter keeps the session visible. Your real spend lives in your own provider dashboard.
Interrupt. Pressing stop sends an ACP session/cancel notification (advisory) and authoritatively concludes the turn in the manager — the same pattern as Kimi Code. Partial streamed text is preserved and status returns to ready.
Routing. A SESSION_LAUNCH (and subsequent send / interrupt / terminate / change-provider) with provider: 'hermes' is dispatched to hermesAcpSessionManager through the dispatch maps derived from its ONE entry in engine-registrations.ts — the same entry supplies its send route, the shared ACP strategy. The session row stores provider: 'hermes' in its DB column; the sessions.provider validation triggers are refreshed from the provider registry at boot, so the id is accepted without a dedicated migration (the 2026-06 migration that first admitted it remains as history). restartResumable: false excludes Hermes from the crash/restart-resume nets (the ACP session state lives in the child, not in a persisted external id the next child can resume from) — the wiring grid's crash-restart cell reads missing for it, honestly.
Capabilities. hermes is declared with { images: true, mcp: true, cloud: false, sshRemote: false, permissionPrompts: false, multiTurn: true }. images: true and mcp: true are ceilings, not promises: the shared slim ACP base reads what the running hermes acp child advertised on its initialize handshake and delivers only that — inline ACP image blocks when it advertised image prompts (otherwise the image is withheld and a visible note is posted in the session), and the project's resolved MCP servers on session/new through the shared in-band connector (remote HTTP servers only when it advertised that transport; if the child refuses to start with the servers it is started once more without them, and the session says so). No SSH remote, no permission-prompt interception (auto-approve), and multiTurn: true is genuinely true (native ACP session memory — the -z regression that made this a lie is fixed).
Verified live against hermes acp (2026-08-01)
Multi-turn memory was confirmed end-to-end with the ACP transport: turn 1 "favorite color is teal" → agent responded "got it"; turn 2 "what color?" → agent replied "teal". This directly validates the fix: under the old -z one-shot transport, turn 2 would have produced no memory of turn 1.
Files
- src/main/services/engines/hermes-acp-session-manager.ts — a ~20-line config subclass of the shared
SlimAcpSessionManagerbase (slim-acp-session-manager.ts — F016, shared with Kimi Code; itself overBaseExternalSessionManager); supplies theHermesAcpClientfactory + handshake predicate + config strings (singletonhermesAcpSessionManager) - src/main/process/hermes-acp-client.ts — spawns
hermes acp --accept-hooksand drivessession/new/session/prompt/session/cancel/ graceful stop over the sharedSlimAcpSessionClient, which performs the one ACPinitializehandshake and keeps what Hermes advertised (acp-capabilities.ts reads it); reuses the provider-agnosticAcpClienttransport andacp-update-translator - src/main/services/hermes-binary-resolver.ts — locate
hermes(30s slow-probe + resolve-by-existence + the%LOCALAPPDATA%\hermes\venv\Scripts/$HERMES_HOMEcandidates) - src/main/services/provider-setup/provider-readiness.ts + src/main/services/providers/main-registry.ts — the 2-gate readiness (toggle + binary, no key)
- src/shared/providers/registry.ts — the
hermesdescriptor (runtimeKind: 'persistent-external',pickerOrder: 7,restartResumable: false,costReporting: 'none'); the single source the picker, badge, and Zod enums all derive from - src/main/services/providers/engine-registrations.ts — Hermes's ONE registration (manager + the shared ACP send strategy); session-manager-registry.ts reads the dispatch maps derived from it
- src/main/db/sessions-provider-allow-list.ts — the boot-time refresh that keeps the
sessions.providertriggers equal to the registry (the dated 2026-06 migration that first admitted'hermes'is history, not a step) - src/renderer/src/components/ui/HermesIcon.tsx + src/renderer/src/features/sessions/ProviderBadge.tsx (amber pill) + src/renderer/src/features/sessions/ChangeProviderButton.tsx — icon + per-launch switcher
- src/renderer/src/features/settings/sections/accounts/AccountSettings.tsx — the Hermes (CLI provider) Settings section: allow-toggle + the install/setup card (no key field)
- .claude/memory/contracts/provider-registry-contract.md — the feature contract (8 invariants + safe-change checklist)
- tests/unit/process/hermes-acp-client.test.ts — locks the ACP client: spawn args, handshake, auth-error detection, permission option selection, graceful stop
- tests/unit/services/hermes-acp-session-manager.test.ts — locks the session manager: lazy spawn, turn dispatch, stall watchdog, interrupt
Comparison with other providers
| Concern | Hermes | Kimi Code | Gemini |
|---|---|---|---|
| Auth | None in Omniscio (Hermes's own config.yaml key) | Kimi Code CLI login (~/.kimi-code/) |
Google API key (GEMINI_API_KEY) |
| Underlying model | Your choice (hermes setup) |
Kimi Code default model | Gemini |
| Process model | Persistent hermes acp child (ACP) |
Persistent kimi acp child (ACP) |
Persistent gemini --acp child (ACP) |
| Streaming | Token-by-token (ACP session/update JSON-RPC) |
Token-by-token (ACP JSON-RPC) | Token-by-token (ACP JSON-RPC) |
| Multi-turn memory | Native (ACP session — real, verified 2026-08-01) | Native (ACP session) | Native (ACP session) |
| Cost emitted | No (records $0) | No (records $0) | No (Google-billed) |
| Images | Inline ACP blocks when the child advertises them, else a note | Same (shared slim ACP base) | Inline ACP blocks |
| MCP servers | Project servers on session/new when advertised |
Same (shared slim ACP base) | Yes (in-band connector) |
| Readiness gates | 2 (toggle + binary, no key) | 2 (toggle + binary, no key) | 3 (toggle + binary + key) |
| Per-project default | Yes | Yes | Yes |
| Session-header pill | Amber "Hermes" | Kimi Code mark | Gemini bloom |
restartResumable |
false (ACP session state lives in the child) |
false |
N/A (has its own --resume <uuid>) |
Related
- kimi-code-provider.md — its slim-ACP twin: same
SlimAcpSessionManagerbase (hermes acpvskimi acp), same 2-gate no-key readiness, same handshake-gated images + MCP servers, same auto-approve v1 posture. (Not kimi-provider.md — that is the Kimi MODEL run through the Claude CLI.) - ai-providers.md — the cross-provider overview
Last verified 2026-10-06