Skip to content
Agentic Control Plane

Hermes Agent is now the easiest coding agent to govern with ACP

David Crowe · 6 min read
governance hermes-agent nous-research coding-agents agentic-control-plane plugin-launch

Hermes Agent — Nous Research’s terminal-native coding agent — now has first-class ACP support via the new hermes-acp Python plugin. Three commands to install:

pip install hermes-acp
hermes plugins enable acp
hermes-acp login

That’s it. No feature flag dance. No MCP connector supplement to cover the tools your hook can’t see. No “wait, does this fire for apply_patch too?” footnote. Every Hermes tool call — terminal, file, web, browser, vision, cron, every custom skill — flows through your ACP workspace from the first restart.

Hermes turned out to be the cleanest integration we’ve built. This post is about why, and what it tells you about the future of governable coding agents.

The state of hook coverage in 2026

We’ve now shipped ACP integrations for four major coding-agent harnesses. They cover wildly different fractions of the tool surface:

Harness What pre_tool_call actually intercepts Feature flag?
Claude Code All native tools + MCP No
Codex CLI Bash only. Read/Edit/Write/web fetch/MCP do not fire. Yes ([features].codex_hooks = true)
Cursor Most native tools. Some built-ins (e.g. Web Search) don’t emit. Bugs filed. No
Hermes Everything. Native and custom. Sync hooks, on by default. No

This isn’t a vendor scoreboard for its own sake. It’s a real, structural difference in what governance means on each platform.

On Codex, “I’ve governed my agent” today means “I’ve governed shell commands my agent runs” — which is most of the destructive-action risk (rm -rf, gh repo delete, psql DROP TABLE), but not all of it. File-edit governance on Codex requires routing edits through an MCP connector ACP also installs. It’s a real solution, but it’s a two-layer solution.

On Hermes, “I’ve governed my agent” means “I’ve governed every tool call.” Period. No supplementary layer.

Why Hermes ended up here

Hermes’s plugin system was designed for this. Where Claude Code’s hooks evolved out of a “shell out and pipe JSON” pattern (and Codex’s are essentially a port of that), Hermes hooks are first-class Python callbacks: register(ctx) registers a function that Hermes calls in-process before dispatching a tool call. The hook receives the tool name, the arguments, the session ID. Return a {"action": "block", "message": ...} and Hermes won’t run the call.

That design — in-process Python rather than out-of-process shell — has three consequences worth noting:

  1. Hook coverage is automatic for every tool the agent has. There’s no “but does the hook fire for this one?” carve-out, because every tool dispatcher goes through the same code path. Adding a new built-in or custom skill doesn’t create a governance gap.

  2. Hooks are synchronous. The tool call blocks until the hook returns. We bound the worst case with a 4-second HTTP timeout to the ACP gateway, fail open beyond that, and emit a stderr warning when we do — same fail-open posture as the Claude Code plugin. Sync hooks rule out async fire-and-forget patterns, but for a governance hook that’s the correct trade-off.

  3. The plugin must be a Python module loadable by Hermes. We could not ship the same govern.mjs we ship to Claude Code / Codex / Cursor. That’s why this integration is a separate pip install, not a curl -sf … | bash. (We thought about wrapping the pip step in the universal installer. It’s a worse UX — bash silently shelling out to whichever Python is on PATH, two uninstall paths, confusing failure modes. Don’t mix install paradigms.)

How the hermes-acp plugin works

Two registered hooks, both calling the same ACP gateway endpoints as the Claude Code / Codex / Cursor plugins:

  • pre_tool_call → POST /govern/tool-use. Server returns allow / deny / ask. deny and ask block the tool call with a system message; allow passes through. The plugin sends X-GS-Client: hermes-plugin/<version> so per-client policies and dashboard filters work the same way they do for the other harnesses.

  • post_tool_call → POST /govern/tool-output. Observational only. Server-side audit, redaction logging, and DLP scanning all run, but the redaction result isn’t propagated back to the agent’s context — that’s a Hermes limitation, not an ACP limitation. The post_tool_call return value is ignored by design in Hermes today.

The plugin is zero-dependency — uses Python’s stdlib urllib for HTTP. No requests, no httpx, no aiohttp. That matters more than it sounds: every transitive dep on a governance plugin is a credential-adjacent supply-chain target, and the value of a thin wrapper over an HTTP API is being a thin wrapper.

What you’ll see in the dashboard

A new hermes-plugin row on cloud.agenticcontrolplane.com/agents, with activity tagged by Hermes’s task_id (its session identifier). The activity log shows:

  • tool_nameterminal, web_search, read_file, plus any custom skill names
  • tool_input — the dict the model passed
  • tool_output — the result, truncated to 200 KB
  • duration_ms — Hermes’s measured execution time
  • Standard ACP attribution — workspace, user, policy decisions, delegation chain

Same shape as the Claude Code / Codex / Cursor log rows. Same policies apply. Cross-harness teams can mix freely.

Two real gotchas to know about

post_tool_call is observational only. If your governance model depends on catching a secret in terminal output before it reaches the model, Hermes can’t apply the redaction back to the agent’s context today. ACP still logs the redaction server-side for post-hoc review and DLP analytics — you just don’t get the inline rewrite that Claude Code’s PostToolUse supports. Most policy violations you actually care about are catchable at pre_tool_call anyway.

No native “ask user” semantic. Hermes only distinguishes block / not-block. When the ACP server returns decision: "ask", the plugin renders it as a block with the message "[ACP] Approval required: …; approve in the ACP dashboard and retry." The user reviews and approves out-of-band, then retries. Adding a /acp-approve slash command via Hermes’s register_command API would give a richer inline UX — open issue, PR welcome.

What this means for the agent landscape

The harnesses with the cleanest governance stories aren’t always the ones with the biggest installed base — they’re the ones that designed for it from day one. Hermes’s plugin system makes governance plug-in-able by construction. Claude Code’s hooks have been extended responsibly since they shipped. Codex’s hooks are explicitly marked Stage::UnderDevelopment and it shows in coverage.

If you’re building a new coding agent and want to be governable: pick a hook surface that fires for every tool dispatch, ship it on by default, make block the only operation a hook return value needs to encode, and document the contract. Hermes did all four and it shows.

Try it

pip install hermes-acp
hermes plugins enable acp
hermes-acp login

Full install guide: /integrations/hermes.

If you’re already running ACP for Claude Code / Codex / Cursor, the same ~/.acp/credentials works — hermes-acp login is idempotent and will short-circuit if you’ve already authenticated. One workspace, every harness.

Get the next post
Agentic governance, AgentGovBench updates, the occasional incident post-mortem. One email per post. No marketing fluff.
Share: Twitter LinkedIn
Related posts

← back to blog