Docs Frameworks

Hermes Agent (Nous Research)

Status: verified. The adapter ships in kiff-guard and passes the conformance suite. The seam was source-verified against the NousResearch/hermes-agent source on main, not just the docs — and a doc-vs-source discrepancy was resolved in favor of the source (see below).

Shape: inverted-control. Hermes runs the tool after the hook returns; the hook only votes. So the adapter uses Guard.observe() / Guard.decide_only(), not a run callback. See how the guard works.

Hermes is a CLI-first agent that takes real, irreversible actions (terminal, code execution, file writes, messaging gateways) — exactly the “actor takes consequential action” profile KIFF governs.

Install

The guard ships to Hermes as a plugin — a directory with plugin.yaml + __init__.py exposing register(ctx). No fork, no monkeypatch.

pip install "git+https://github.com/kiffhq/kiff-guard.git#subdirectory=packages/python/kiff-guard"

Then create the plugin at ~/.hermes/plugins/kiff-guard/.

Observe — audit with zero config

__init__.py:

from kiff_guard import Guard
from kiff_guard.adapters.hermes import register_kiff_guard

_GUARD = Guard(mode="observe")        # zero-config audit; no KIFF account

def register(ctx):
    register_kiff_guard(ctx, _GUARD)

The hook fires before every tool (terminal, browser, code-exec, file writes, MCP) in both the CLI and the gateway, records a receipt, and never blocks.

Activate

from kiff_guard import export_yaml
print(export_yaml("my-domain", _GUARD.catalog))

Review and activate in the dashboard.

Enforce — govern at runtime

Build the guard with a client and mode="enforce":

from kiff_guard import Guard, HTTPClient, ToolMap

client = HTTPClient(api_key="kiff_live_...", tool_map=ToolMap().bind(...))
_GUARD = Guard(client=client, tenant="<tenant>", agent="hermes", mode="enforce")

On a withheld decision the adapter returns Hermes’ {"action": "block", "message": ...} directive — Hermes short-circuits the tool and hands message to the model as the tool’s error result. The tool never runs. Enforce fails closed on a guard error by default; pass fail_closed=False to override.

The seam (verified)

The pre-execution seam is the pre_tool_call plugin hook. In source (model_tools.pyhandle_function_call), Hermes calls get_pre_tool_call_block_message(...) before dispatch; a non-None block result short-circuits the tool. The hook fires exactly once per tool execution and the first block wins.

Doc-vs-source discrepancy (resolved). Hermes’ plugin-build guide lists pre_tool_call’s return as “ignored” (observer-only), but the hooks reference says it can block — and the source confirms the hooks reference is correct. The block directive is supported and stable. KIFF complements Hermes’ own DANGEROUS_PATTERNS local check by adding the tenant-wide policy + audit.