@waggle/hive-mind-hooks-hermes
Silent-capture shim that wires Hermes (NousResearch/hermes-agent)
lifecycle hooks into hive-mind
frames. Every Hermes session deterministically captures session-start /
prompt / response events into your personal memory via hive-mind-cli — the
same every-turn pattern proven by @waggle/hive-mind-hooks-claude-code, built
on the shared @waggle/hive-mind-hooks-core foundation.
Hermes's hook config is a YAML installer with create-if-missing
semantics. It targets the SHELL-HOOKS system — the top-level hooks:
block in ~/.hermes/config.yaml. It does not touch Hermes's two other
"hooks" systems (the directory-based gateway hooks under ~/.hermes/hooks/,
or the in-process plugin hooks) — only the shell-hooks block.
Not hook parity with claude-code. Hermes ships only 3 lifecycle hooks — there is no PreCompact event — and splits SessionStart across two events. See the Capture fidelity table below.
Install
npx @waggle/hive-mind-hooks-hermes install
# Windows / production: pin the CLI path
npx @waggle/hive-mind-hooks-hermes install --cli-path "C:\\path\\to\\hive-mind-cli\\dist\\index.js"
The installer additively merges hive-mind shell-hook entries into
~/.hermes/config.yaml (creating the file if absent), preserving any existing
hooks you have, and writes a pointer + literal byte-identical backup so
uninstall is exact. (YAML re-serialization loses comments and key ordering, so
uninstall restores the original bytes rather than a re-serialized diff.)
Headless / gateway consent (IMPORTANT). Hermes keeps a first-use consent allow-list keyed on the exact hook command string. Under a headless / non-TTY launch the hooks register only if
hooks_auto_accept: trueis in the config (the installer seeds this by default) orHERMES_ACCEPT_HOOKS=1is set — otherwise they silently never register. Pass--no-auto-acceptto manage consent yourself.
npx @waggle/hive-mind-hooks-hermes verify # smoke-check
npx @waggle/hive-mind-hooks-hermes uninstall # byte-identical restore (or remove if we created it)
Capture fidelity
| Lifecycle | Hermes event(s) | Status | Notes |
|---|---|---|---|
| SessionStart (recall + inject) | on_session_start (observer) + pre_llm_call (is_first_turn) |
full (split) | observer side is a no-op; inject side fires on the first turn only and appends { "context": "..." } to the user message (not the system prompt — preserves the prefix cache) |
| UserPromptSubmit (save temporary) | pre_llm_call |
full | the user text arrives at extra.user_message; saved every turn |
| Stop (summarize + save) | post_llm_call |
full | the assistant text arrives at extra.assistant_response; on_session_finalize is gateway-only and is not used |
| PreCompact (compact memory) | — (none) | opt-in approximation | Hermes ships no compaction hook (VALID_HOOKS has no compact entry) — there is genuinely nothing to bind. Set WAGGLE_HERMES_COMPACT_ON_STOP=1 (default off) to approximate it from the per-turn Stop hook, time-gated by WAGGLE_HERMES_COMPACT_WINDOW_MIN (minutes, default 10) so it runs at most once per window |
Disclosures:
- No PreCompact event at all. Hermes has no compaction hook, so the
cleanup_framesmaintenance step that claude-code runs on PreCompact does not run under Hermes by default. Memory still accrues correctly; only the periodic compaction nudge is absent. Opt-in: setWAGGLE_HERMES_COMPACT_ON_STOP=1to approximate it from the per-turn Stop hook, time-gated byWAGGLE_HERMES_COMPACT_WINDOW_MIN(minutes, default 10) so the maintenance pass fires at most once per window. - SessionStart is split across
on_session_start(observer) andpre_llm_call(inject). One compiled script is registered under both; it gates injection onis_first_turnso it injects once per session, not every turn. - Block/inject is via stdout JSON, not exit codes — Hermes has no
exit-code-2 contract. Our hooks are capture-only: they emit
{}(or the SessionStart{ "context": ... }) and exit 0. - Headless consent — without
hooks_auto_accept: true(seeded by default) orHERMES_ACCEPT_HOOKS=1, the hooks silently never register under a headless launch.
How it works
Each hook is a short-lived Node subprocess. Hermes spawns the configured
command (shlex.split + shell=False), pipes the event JSON to the hook's
stdin, and reads optional JSON back from stdout. The hook shells to
hive-mind-cli to recall or save frames, then exits 0. Fail-open: if
hive-mind-cli is unreachable or the payload is malformed, the hook logs to
stderr and exits 0 — Hermes is never blocked.
License: Apache-2.0.