Hermes Agent permissions: governing every tool call with ACP
Hermes Agent, the terminal coding agent from Nous Research, works with ACP through the acp-hermes Python plugin. Three commands install it:
pip install acp-hermes
hermes plugins enable acp
acp-hermes login # if this errors about editor/ACP mode, use: python -m acp_hermes.cli login
After a restart, every Hermes tool call is checked against your ACP workspace before it runs. That includes terminal, file, web, browser, vision, cron and your own skills. There is no feature flag and no second connector to cover the tools the hook can’t see.
Of the harnesses we’ve wired up, Hermes was the simplest. Here is why.
Hook coverage differs a lot between harnesses
ACP works with about fifteen coding-agent harnesses (see the coverage matrix for the current list). They differ in how many tools their pre-call hook sees. A few examples, as of November 2026:
| Harness | What the pre-call hook sees |
|---|---|
| Claude Code | All native tools and MCP |
| Codex CLI | Shell, apply_patch edits, MCP and other local tools on current builds. Shell only on older builds. Hosted tools like web search never reach a hook. |
| Cursor | Most native tools. Some built-ins don’t emit events (bugs filed). |
| Hermes | Everything, native and custom. |
This matters because “my agent is governed” means different things on each one. If the hook doesn’t fire for a tool, your rules never see that tool. On Hermes there is no such gap to work around.
Why Hermes ended up this way
Hermes hooks are Python callbacks. A plugin’s register(ctx) hands Hermes a function, and Hermes calls it in-process before it runs a tool. The hook gets the tool name, the arguments and the session ID. If it returns {"action": "block", "message": ...}, Hermes skips the call.
That design has three results:
-
Coverage is automatic. Every tool goes through the same dispatcher. Adding a new built-in or custom skill doesn’t open a gap.
-
Hooks are synchronous. The tool waits until the hook answers. A governance hook should work that way.
-
The plugin has to be a Python module. We couldn’t reuse the
govern.mjshook file we ship for other harnesses. In a connected setup, the installer now finds Hermes, picks the right Python interpreter, installsacp-hermesand enables it. A directpip install acp-hermesstill works for local or manual setups.
What the plugin does
Two hooks, calling the same gateway endpoints as the other harness plugins:
-
pre_tool_callposts to/govern/tool-useand gets backallow,askordeny. A deny or an ask blocks the call and shows a message. An allow passes through. The plugin sendsX-GS-Client: hermes-plugin/<version>, so per-client rules and dashboard filters work as they do elsewhere. -
post_tool_callposts to/govern/tool-output. The gateway scans and logs the result, but Hermes ignores what this hook returns, so ACP can’t rewrite the result before the model reads it. Hermes does have atransform_tool_resulthook that could do it. The plugin doesn’t register it yet.
The plugin has no dependencies beyond Python’s standard library (urllib). Fewer dependencies means less supply-chain exposure for something that handles credentials.
What you see in the dashboard
A hermes-plugin row on cloud.agenticcontrolplane.com/agents, with activity grouped by Hermes’s task_id. Each row has:
tool_name, such asterminal,web_search,read_fileor a custom skilltool_input, the arguments the model passedtool_output, truncated to 200 KBduration_ms- the usual ACP fields: workspace, user, decision
These are the same fields the Claude Code, Codex and Cursor rows have, and the same rules apply. A team can mix harnesses in one workspace.
Two limits
ACP can’t rewrite tool output on Hermes today. Say a terminal command prints a secret. ACP logs the finding, but the secret still reaches the model. Claude Code can swap in a redacted result. Stop most problems at the pre-call check, before the command runs.
A hold becomes a block. Hermes only knows block or don’t block. When the gateway answers ask, the plugin blocks the call with a message saying approval is required. You approve it on the Approvals page or from the approval email, then ask the agent to retry. An unanswered request expires and counts as denied. Only Claude Code shows a hold as an in-session prompt today.
Try it
pip install acp-hermes
hermes plugins enable acp
acp-hermes login
The full guide is at /integrations/hermes. If you already use ACP with another harness, acp-hermes login sees your existing ~/.acp/credentials and skips the sign-in. One workspace covers every harness.
Running Hermes? One command adds a hook. Each tool call it sees is recorded, and a force-push, destructive SQL or curl | sh is blocked until you approve it on the console or from the email.
curl -fsSL https://agenticcontrolplane.com/install.sh | bash
irm https://agenticcontrolplane.com/install.ps1 | iex
What the installer writes · Hermes guide · free up to 5 agents