Hermes: onboarding, rollback, and systemd recovery¶
Editions: OSS, Cloud, Enterprise. Unless stated otherwise, everything on this page ships in OSS.
Hermes is a supported managed agent. This page is the operational playbook for connecting it to Preloop, undoing that connection, and recovering when tools stay gated after a config change. The systemd-first kill order comes from issue #828.
Hermes is Nous Research's
open-source agent. It supports MCP servers natively through its
mcp_servers configuration block. Once onboarded, every Hermes tool call
passes the Preloop safety layer, sensitive calls can wait for a human
approval (console, mobile, watch, Slack, email), each Hermes process gets a
durable runtime credential and appears in the Agents view, and tool calls and
model spend are attributed to that Hermes runtime principal.
Install Hermes from upstream (see the
Hermes docs for current
options); it keeps its configuration in ~/.hermes/config.yaml.
Onboarding¶
export PRELOOP_DISABLE_TELEMETRY=true
preloop login
preloop agents onboard Hermes
preloop agents validate Hermes
preloop agents onboard Hermes discovers ~/.hermes/config.yaml or
~/.hermes/config.yml (or an installed-but-unconfigured Hermes tree),
backs up the file under the Preloop config directory, writes a
preloop.control block plus a managed MCP server, and can rewrite model
settings to Preloop's OpenAI-compatible gateway. It then installs
preloop-hermes-plugin into Hermes' virtualenv and runs
hermes gateway restart so the running process reloads what was written.
Use --skip-live-validate only when you cannot reach the control plane.
--model selects which account model the gateway rewrite should pin.
Plugin-only (native tool approvals and the Talk channel, no model or MCP rewrite):
That command now restarts the Hermes gateway the same way onboarding does.
What onboarding writes and restarts¶
On disk, onboarding updates the discovered Hermes YAML:
preloop.controlwithcontrol_ws_url, the runtime bearer token, and principal identity- a managed
preloopentry undermcp_servers - optional
modelrewrite to Preloop's/openai/v1gateway
The CLI writes ~/.hermes/config.yaml when it has to create a file. If a
.yml sibling already exists, that is the file it edits.
The running Hermes process does not pick that up by magic. Onboarding
therefore runs hermes gateway restart. Offboard, preloop agents restore
Hermes, and preloop agents install-plugin Hermes call the same helper.
If hermes is not on PATH, the command warns and continues; run
hermes gateway restart yourself.
When systemd user units named hermes-* are present (Linux only, best
effort), the CLI prints them and the exact restart command, for example:
Found systemd user units that can respawn Hermes: hermes-gateway.service, hermes-matrix-monitor.service
Restart with: systemctl --user restart hermes-gateway.service hermes-matrix-monitor.service
Stop them before killing processes: systemctl --user stop hermes-gateway.service hermes-matrix-monitor.service
Offboarding and restore¶
Offboard is reversible. It restores the backed-up Hermes config, archives the managed agent in Preloop, and restarts the gateway so the live process drops the control block.
The config backup is not next to config.yaml. Onboarding stores it under
the Preloop config directory:
(PRELOOP_CONFIG_DIR relocates that tree.) Offboard restores from that
path. To restore the backup without archiving the managed agent:
That is the CLI command. There is no preloop agents onboarding restore
alias.
Moving ~/.preloop aside is an extra operator step, not something
offboard does. If you do that, keep a copy so you can move it back before
preloop agents restore Hermes.
Uninstalling the plugin package is also optional and separate:
# use the Hermes virtualenv pip, not system pip
"$HERMES_VENV/bin/pip" uninstall -y preloop-hermes-plugin
Why a running gateway must be restarted¶
The plugin re-reads YAML on each failed control-block lookup. It does not
keep a stale "missing preloop.control" result in memory. Two other facts
still make a live process ignore a file you just edited:
- Discovery can pick a different file than onboarding wrote. The
plugin searches
$HERMES_HOME/config.yamlandconfig.yml, then~/.hermes/config.yamlandconfig.yml. A systemd user unit often has a differentHERMES_HOME(or a.ymlsibling) than your interactive shell. Until recently the plugin did not prefer the file that actually containspreloop.control, so a gateway started by systemd could fail closed withmissing preloop.control config blockwhilepreloop agents validate Hermesagainst the onboarded file looked fine. That matches "intermittent, then consistent" as systemd respawns win over a shell-started Hermes. - Successful settings are cached for the life of the process. After a control block loads, later tool calls reuse it. Stripping or rewriting the file does not unload that process. Restart the gateway (and any systemd unit that will spawn another copy).
A liveness probe inside the plugin cannot see that systemd is about to respawn a sibling with a different environment. Restart the process that will actually serve tools.
Stop systemd before killing processes¶
Killing hermes_cli.main or the desktop GUI first is not enough when
user units are enabled. systemd starts them again in seconds, still with
the unit's environment.
Order that works (Linux, credited to issue #828):
export PATH="$HOME/.local/bin:$PATH" PRELOOP_DISABLE_TELEMETRY=true
preloop agents offboard Hermes --yes
# 1) Stop the respawners first
systemctl --user stop hermes-gateway.service hermes-matrix-monitor.service
sleep 2
# 2) Then kill leftover processes and confirm they are gone
pkill -f "hermes_cli.main" || true
pkill -f "Hermes" || true
sleep 2
ps -eo pid,args | grep -E 'hermes_cli|Hermes' | grep -v grep || echo ALL_GONE
# 3) Start one fresh process so it reads the restored config
hermes gateway restart
# 4) Bring the user units back if you still want Matrix/messaging on boot
systemctl --user restart hermes-gateway.service hermes-matrix-monitor.service
Unit names vary. Use the names the CLI printed, or:
Prove the plugin sees the right config¶
If tools still gate, the fail-closed message now names the file that was
read and whether HERMES_HOME / HOME were set, for example:
Preloop approval unavailable: missing preloop.control config block
(read /home/you/.hermes/config.yaml; HERMES_HOME=<unset>, HOME=/home/you).
run `preloop agents validate Hermes`; if the path differs from the one
onboarding wrote, restart the Hermes gateway and any systemd user units
(`systemctl --user restart hermes-gateway.service`)
Compare that path with the file onboarding reported. If they differ, restart the gateway and the systemd units so the live process uses the same discovery environment you just validated. The gate still fails closed; only the message changed.
Model routing versus tool routing¶
Two layers, installed differently:
- Tool routing (the plugin). Native Hermes tools (
terminal,read_file, and the rest) go throughpre_tool_callto Preloop approvals. MCP tools are a different path: they need the managed MCP server from a full onboard. - Model routing (full onboard).
preloop agents onboard Hermespoints Hermes' model client at Preloop's gateway. That is what produces per-agent spend, budgets, and allowed-model lists. It can also change which model feels "fast" if the gateway pin is not the model you used directly.
Plugin-only / MCP-proxy-only keeps direct model calls. Full onboard
routes models through the gateway. Offboard restores the backed-up
model block so direct routing returns.
Informational startup lines¶
These lines are not errors. They show up during install or when a user unit already exists:
install stamp:records which Hermes build launched. Useful when comparing a GUI binary with a gateway unit.DEP0180is a Node.js runtime deprecation notice from a dependency. It does not mean Preloop onboarding failed.UnitExistsfrom systemd meanshermes-gateway.service(or anotherhermes-*unit) is already installed. Enable/start still works;systemctl --user restartis the reload you want after a config change.
If tools are gated, ignore these lines and use the verify path above.
Manual configuration¶
If you would rather wire Hermes by hand, create an API key under
Settings > API Keys in the console and add Preloop to the mcp_servers
block of ~/.hermes/config.yaml:
mcp_servers:
preloop:
url: https://preloop.ai/mcp/v1
headers:
Authorization: Bearer YOUR_API_KEY_HERE
enabled: true
For a self-hosted stack, replace https://preloop.ai with your own URL.
hermes mcp list should then show preloop. A hand-written entry gives you
tool routing only: no Agent Control block, no model gateway rewrite, and no
config backup to restore.
Troubleshooting¶
preloop agents discoverdoes not find Hermes. Discovery looks for~/.hermes/(or~/.hermes/hermes-agent,~/.hermes/sessions) and~/.local/bin/hermes. Install Hermes or create one of those paths first.- Tools are missing. The key Hermes presents needs the
mcp:readandmcp:writescopes (onboarding mints them), and no subject-scoped tool list may be hiding the tools you expect. See Subject-Scoped Governance. - Tools stay gated after a config change. Restart the gateway and any systemd user units, as described above.