headroom/plugins/hermes/README.md
jimu 058bcedab8
feat(plugins): Hermes agent headroom_retrieve plugin (#824)
## Summary

Implements the Hermes-side retrieval plugin proposed in #796 (as invited
— thanks for the quick response!).

When Hermes routes traffic through `headroom proxy`, compressed markers
are a one-way street: Hermes registers its own tools, so it never gets
the `headroom_retrieve` CCR tool that Claude Code receives via MCP
injection. In practice the model either re-runs the original command or
— observed in the wild — treats `ccr:abc123` as a file path and tries to
`cat` it.

This plugin uses Hermes's user-plugin system (`~/.hermes/plugins/`) to
register a native `headroom_retrieve` tool that calls the proxy's `POST
/v1/retrieve` endpoint.

## What's included

- `plugins/hermes/headroom_retrieve/` — `plugin.yaml` + `__init__.py`
(single-file, httpx, ~100 lines)
- `plugins/hermes/README.md` — install steps and proxy-side
recommendations

## Design notes

- **Both marker formats covered**: Kompress emits `[N items compressed
... hash=KEY]`, SmartCrusher's opaque-blob walker emits
`<<ccr:HASH[,KIND,SIZE]>>`. The tool description teaches both and
explicitly says markers are NOT file paths; the handler normalizes
whole-marker input (`<<ccr:abc,base64,4.5KB>>` → `abc`).
- **Re-compression loop guard**: retrieved originals travel back through
the proxy on the next request and get re-compressed into a fresh marker,
looping forever. README documents
`HEADROOM_EXCLUDE_TOOLS=read_file,headroom_retrieve` as the fix (Hermes
tool names don't match `DEFAULT_EXCLUDE_TOOLS`, which targets Claude
Code's `Read`/`Grep`/...).
- **Actionable failure modes**: 404 (TTL expired / proxy restarted) and
connection-refused both return guidance to re-run the original command
rather than retry.

## Relationship to existing PRs

Complementary to #707 / #556 (`headroom wrap hermes`, proxy-side): those
launch/route Hermes through the proxy; this gives the agent the
retrieval capability once it's routed. Notably #707 disables CCR tool
injection in Hermes mode precisely because Hermes must register its own
tool — this plugin is that registration.

## Testing

Running in production on macOS (headroom 0.23.0, pipx) and Linux
(0.22.4, systemd) for a day. Verified: fresh-marker retrieval roundtrip,
whole-marker hash normalization (6 input shapes), expired-hash 404
messaging, proxy-down messaging, and end-to-end via live Hermes sessions
(fresh ≥500B `read_file` returns original with the documented exclude
config).

Closes #796

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: akb4q <zhunyunjiang@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 18:43:10 -05:00

2.9 KiB

Hermes Agent Integration

CCR retrieval plugin for Hermes Agent (Nous Research). Gives Hermes a native headroom_retrieve tool so compression markers produced by the headroom proxy are no longer a black box — the agent can fetch the original content back on demand instead of guessing or re-running commands.

Why this is needed

When Hermes routes its LLM traffic through headroom proxy, large tool outputs get compressed into markers like:

[1500 items compressed to 50. Retrieve more: hash=abc123]   # Kompress path
<<ccr:abc123>> / <<ccr:abc123,base64,4.5KB>>                # SmartCrusher opaque-blob path

Claude Code users get the headroom_retrieve MCP tool injected automatically. Hermes registers its own tools, so without this plugin the markers are irreversible from the agent's point of view — in practice the model either re-runs the original command (wasting tokens/time) or, worse, treats ccr:abc123 as a file path and tries to cat it.

This plugin closes the loop by calling the proxy's POST /v1/retrieve HTTP endpoint directly. It complements (does not overlap with) headroom wrap hermes proxy-side support.

Install

  1. Copy the plugin into Hermes's user plugin directory:

    mkdir -p ~/.hermes/plugins
    cp -r headroom_retrieve ~/.hermes/plugins/
    
  2. Enable it in ~/.hermes/config.yaml:

    toolsets:
      - hermes-cli
      - web
      - headroom        # add this
    
    plugins:
      enabled:
        - headroom_retrieve
    

    Note: once the plugins.enabled key exists it acts as an explicit allowlist — list any other user plugins you already rely on.

  3. Restart the Hermes gateway / TUI (plugin discovery is cached per process).

Hermes tool names don't match headroom's built-in DEFAULT_EXCLUDE_TOOLS (which protects Claude Code's Read/Grep/Edit/...), so two exclusions are strongly recommended on the proxy side:

HEADROOM_EXCLUDE_TOOLS=read_file,headroom_retrieve
  • read_file — Hermes's file reads are reference data the agent needs verbatim, same rationale as Claude Code's Read.
  • headroom_retrieve — without this, retrieved originals get re-compressed on the next request, producing an endless marker→retrieve→marker loop.

Behavior

  • Accepts the bare hash or the whole marker — <<ccr:abc123,base64,4.5KB>>, ccr:abc123, and hash=abc123 are all normalized to abc123.
  • Optional query parameter filters very large results via the proxy's BM25 search.
  • Clear, actionable errors: expired hash (TTL) and proxy-unreachable cases both tell the model to re-run the original command instead of retrying blindly.

Requirements

  • headroom proxy running on 127.0.0.1:8787 (edit _PROXY_URL in __init__.py otherwise)
  • httpx (already a Hermes dependency)

Tested against headroom 0.22.4 and 0.23.0 with Hermes Agent on macOS and Linux.