feat: add Hermes (NousResearch hermes-agent) preset and hook installer#1300
Open
Krishnachaitanyakc wants to merge 2 commits into
Open
feat: add Hermes (NousResearch hermes-agent) preset and hook installer#1300Krishnachaitanyakc wants to merge 2 commits into
Krishnachaitanyakc wants to merge 2 commits into
Conversation
Adds first-class support for Hermes' shell-hook protocol against the
post-rewrite agent-preset framework.
Preset (`presets/hermes.rs`):
- Pure parser implementing `AgentPreset::parse`. Handles
`pre_tool_call` / `post_tool_call` for `write_file`, `patch`, and
`terminal`.
- Strict event handling: lifecycle events (`pre_llm_call`,
`on_session_start`, `subagent_stop`, etc.) return `PresetError`
rather than fabricating a phantom file-edit checkpoint.
- `transcript_source: None`. Hermes' shell-hook payload doesn't
surface a transcript path, and the on-disk session storage schema
under `~/.hermes/` is not part of the public hook contract; a
dedicated reader can land in a follow-up.
Installer (`mdm/agents/hermes.rs`):
- Writes `[[hooks.<event>]]` entries into `~/.hermes/config.yaml`
using the documented YAML schema with the `".*"` matcher.
- Sets `hooks_auto_accept: true` at the root so our installed
entries don't trigger Hermes' first-use consent prompt — but only
when the user hasn't explicitly chosen.
- Idempotent — repeat install is a no-op (compared structurally so
YAML round-trip whitespace doesn't cause spurious diffs).
- Token-based ownership matching (`is_git_ai_hermes_command`):
a hypothetical sibling preset like `hermes-pro` is never
misidentified.
- Uninstall removes only hermes entries, removes emptied event
keys, and removes the `hooks` block when empty; user-defined
hooks survive.
Tool classification (`bash_tool.rs`):
- New `Agent::Hermes` variant. `write_file` / `patch` map to
`FileEdit`, `terminal` maps to `Bash`, all else `Skip`.
New dependency:
- `serde_yml = "0.0.12"` for parsing `~/.hermes/config.yaml`.
Hermes is the first supported agent that uses YAML config.
Wiring:
- `presets/mod.rs::resolve_preset` accepts `hermes`.
- `mdm/agents/mod.rs::get_all_installers` includes `HermesInstaller`.
Detection uses `binary_exists` for all three documented entry
points (`hermes`, `hermes-agent`, `hermes-acp`) plus the
`~/.hermes` dotfile fallback.
- `git_ai_handlers` help text lists `hermes`.
- `tests/integration/repos/test_file.rs::AI_AUTHOR_NAMES` and
`test_repo.rs::is_known_checkpoint_preset` learn `hermes`.
Tests: 11 preset unit tests, 20 installer unit tests, 9 integration
tests including 3 full E2E flows asserting `assert_lines_and_blame`.
`cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`,
`RUSTDOCFLAGS=\"-D warnings\" cargo doc --no-deps`, and the relevant
test suites all pass locally.
Closes git-ai-project#1136
CodeQL flags the previous `panic!("...", &events[0])` patterns as
cleartext logging of sensitive information because the Debug
serialization of `ParsedHookEvent` includes `external_session_id`.
Drop the `{:?}` argument; the panic message itself already names
the expected variant, so this matches the existing convention used
by gemini, amp, opencode, etc.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds first-class support for Hermes — NousResearch's Python AI coding agent — against the post-rewrite agent-preset framework. Closes #1136.
Hermes has three hook systems (gateway hooks, plugin hooks, shell hooks). Of these, only the shell-hook system is language-agnostic and integrable from outside the Hermes process; we install into that.
Preset (
presets/hermes.rs)AgentPreset::parse. Handlespre_tool_call/post_tool_callforwrite_file,patch, andterminal.pre_llm_call,post_llm_call,pre_api_request,post_api_request,on_session_start,on_session_end,on_session_finalize,on_session_reset,subagent_stop,transform_tool_result) returnPresetErrorrather than fabricating a phantom file-edit checkpoint.transcript_source: Nonefor v1 — Hermes' shell-hook payload doesn't surface a transcript path, and the on-disk session storage schema under~/.hermes/is not part of the public hook contract; a dedicated reader can land in a follow-up.agent_id.modeldefaults to"unknown"since the shell-hook payload doesn't carry the active model (it lives only in the LLM-call payload, not the tool-call payload).Installer (
mdm/agents/hermes.rs)[[hooks.<event>]]entries into~/.hermes/config.yamlper the upstream YAML schema. Uses the documented".*"matcher (regex match-all).hooks_auto_accept: true— set at the root so our installed entries don't trigger Hermes' first-use consent prompt. Only set when the user hasn't explicitly chosen otherwise (an explicitfalseis preserved).is_git_ai_hermes_command): a hypothetical sibling preset likehermes-prois never misidentified.pre_tool_call: []) and the emptyhooks:block are removed entirely.Tool classification (
bash_tool.rs)Agent::Hermesvariant:write_file/patch→FileEdit,terminal→Bash, all else →Skip.New dependency
serde_yml = "0.0.12"for parsing~/.hermes/config.yaml. Hermes is the first supported agent that uses YAML config; serde_yml is a small, actively-maintained YAML crate.Wiring
presets/mod.rs::resolve_presetacceptshermes.mdm/agents/mod.rs::get_all_installersincludesHermesInstaller. Detection usesbinary_existsfor all three documented entry points (hermes,hermes-agent,hermes-acp) plus the~/.hermesdotfile fallback.git_ai_handlershelp text listshermes.AI_AUTHOR_NAMESandis_known_checkpoint_presetlearnhermes.Test plan
cargo fmt --checkcleancargo clippy --all-targets -- -D warningsclean (no#[allow(...)]annotations added)RUSTDOCFLAGS="-D warnings" cargo doc --no-depscleanpresets::hermes::tests::*) — pre/post forwrite_file/patch/terminal, lifecycle event rejection (10 events), unsupported tool rejection (read_file/search_files), missing field errors (session_id,cwd), invalid JSON, absolute path passthrough,tool_call_idextraction fromextradictmdm::agents::hermes::tests::*) — fresh install (s1), idempotency (s2), preserves unrelated hooks and other settings (s3), updates outdated path (s4), dedup (s5), dry-run (s6), creates parent dir (s7), respects user'shooks_auto_accept: false(s8); uninstall variants u1-u5 including emptied-event-key removal (u4); error handling e1-e4 (invalid YAML, root-must-be-mapping, hooks-must-be-mapping); token-precise ownership matchingtests/integration/hermes.rs) — preset routing, lifecycle/tool rejection sweeps, 3 E2E flows assertingassert_lines_and_blameand session metadata