Skip to content

Hermes (ACP)

Hermes Agent is an open-source agent runtime from Nous Research that speaks the Agent Client Protocol over stdio. Z.E.N. ships a built-in hermes/acp harness — install the binary and any agent: workflow node can dispatch to it.

yaml
nodes:
  - id: research
    agent:
      harness: hermes/acp
      prompt: Find the three most-cited papers on transformer attention from 2025.

Install Hermes

bash
# uvx — recommended; isolates the install, no global Python state
uvx hermes acp --help

# Or via PyPI
pip install --user hermes-agent
hermes --version

Either path leaves a hermes command on your PATH. The Z.E.N. daemon discovers it at boot and probes hermes --version to populate the version field in Settings → Harnesses.

Confirm the wiring

Settings → Harnesses should show:

hermes/acp  [acp]  built-in  Hermes Agent v0.14.0 (2026.5.16)

If the version line says unavailable: …, the daemon couldn't spawn hermes. Two common fixes:

  1. PATH doesn't reach hermes. The daemon (especially when launched via launchd) inherits a stripped PATH. Run which hermes in your terminal, then set the absolute path explicitly:
    # ~/.zen/.env
    ZEN_HERMES_BIN=/Users/you/.local/bin/hermes
  2. You installed under a different name (e.g. hermes-acp or a project-local wrapper). Set ZEN_HERMES_BIN to that path; Z.E.N. will run it with acp as the first arg by default.

Either way, restart the daemon (zen serve) to re-probe.

Verify end-to-end

The repo ships a one-node smoke workflow:

bash
zen workflow run hermes-acp-smoke

You should see a worktree create, the node start, and Hermes reply with "ACP smoke OK". The Agent tab on the run detail shows every translated RuntimeEvent from the session.

Env vars

Independent overrides — no implicit coupling:

VarDefaultWhy
ZEN_HERMES_BINhermesAbsolute path or command name. Set when the daemon's PATH can't find Hermes.
ZEN_HERMES_ARGS["acp"]Replaces the default args list. JSON array or comma-separated. Set if your wrapper expects different positional args.
ZEN_HERMES_ACCEPT_HOOKSunset"1" appends --accept-hooks so Hermes auto-approves shell tools without TTY prompts. Required for shell-using prompts until Z.E.N.'s tool-approval UI ships.
ZEN_HERMES_VERSIONprobedExplicit version stamp. Overrides what hermes --version reports. Useful in tests.
ZEN_DISABLE_HERMES_ACPunset"1" skips registration entirely. The harness disappears from /api/harnesses.

Capabilities surfaced

Hermes' built-in capabilities determine what Z.E.N. exposes through the harness:

CapabilityHermesWhat it enables
Session resumeresume_session: $previous.output.sessionId on an agent: node
Mid-turn cancelCancelling the workflow run sends session/cancel to Hermes
MCP toolsHermes can call any MCP server you've configured for it
Shell toolsHermes runs shell commands via its own permission policy
Model selectionPass model: in the agent block to switch the underlying LLM
Cost capHermes manages its own budget; Z.E.N.'s max_budget_usd is forwarded but not enforced here
SandboxOut-of-process subprocess; sandbox is the OS, not the harness

The actual capability chips on Settings → Harnesses come from this list.

Tool approval

Hermes asks Z.E.N. for permission before running sensitive tools via the ACP requestPermission request. Today Z.E.N. rejects by default — sensitive tools are blocked. Workarounds:

  • ZEN_HERMES_ACCEPT_HOOKS=1 — Hermes auto-approves its own shell hooks, skipping the round-trip. Trade-off: anything Hermes wants runs.
  • Future: Z.E.N. will pause the workflow on a requestPermission and surface an approval modal on the run detail page. Not shipped yet; tracked alongside the agent-node-tab UI work.

What runs vs what doesn't

Hermes ships with ~80 built-in tools + adapters for 22 messaging platforms. Anything that doesn't shell out runs cleanly through ACP today. Things that need TTY interaction (login flows, interactive approvals) won't work over stdio — use Hermes' interactive UI for those, then resume the session id from Z.E.N.

AI that follows a recipe, not a conversation.