feat(hermes): Hermes Agent harness support — eval-verified pre_llm_call bootstrap#2025
Open
obra wants to merge 3 commits into
Open
feat(hermes): Hermes Agent harness support — eval-verified pre_llm_call bootstrap#2025obra wants to merge 3 commits into
obra wants to merge 3 commits into
Conversation
…diff Rebase of PR #1922 onto current dev: the ~14 files of v6.1.0-era codex/release drift are dropped, the porting-guide edits (stale against the post-prune rewrite, no Hermes content) are dropped, and the Hermes surface is kept intact: .hermes-plugin/ (on_session_start bootstrap injection), tests/hermes/ (20 tests, passing), docs/README.hermes.md, references/hermes-tools.md, the Platform Adaptation row, README section, and Python ignores. Known open items from review, unchanged by this rebase: the injection mechanism uses ctx.inject_message from on_session_start, which the official plugin guide does not document (pre_llm_call returning {"context": ...} is the sanctioned path), skills are not registered via ctx.register_skill, and the acceptance transcript predates the fix. Co-authored-by: kumarabd <kumarabd@users.noreply.github.com>
…ill registration
Empirical findings from the quorum eval bring-up (superpowers-evals
docs/experiments/2026-07-23-hermes-target-bringup.md):
- ctx.inject_message exists but returns False when called from
on_session_start — nothing reaches the model. The documented path,
a pre_llm_call hook returning {"context": ...} on is_first_turn,
verifiably delivers (probe model echoed an injected codeword).
- ctx.register_skill requires a pathlib.Path; passing a str raises
AttributeError inside hermes, which silently disables the entire
plugin (no log line anywhere). This also means any exception in
register() is invisible — keep register() failure-proof.
- Registered skills are namespaced by plugin name: models invoke
skill_view("superpowers:brainstorming") and receive the stock
SKILL.md — verified live on GLM 5.2, both install layouts.
The plugin now: resolves skills/ for both the git-clone layout
(.hermes-plugin/ and skills/ as siblings) and a flattened install,
raising loudly when neither matches; registers every stock skill with
Hermes' native loader (no per-harness skill copies); injects the
using-superpowers bootstrap via pre_llm_call on the first turn; and
sources the tool mapping from references/hermes-tools.md instead of
duplicating it. Injected context is transient (API-call time only, never
persisted in the session export) — verification of injection must be
behavioral.
…s to the README section The 20-test suite still exercised the dead on_session_start/inject_message mechanism (17 failures against the rewritten plugin). Rewritten for the real contract: pre_llm_call registration + first-turn-only context return, register_skill receiving pathlib.Path (the conftest mock now raises on str, mirroring hermes' AttributeError that silently disables a plugin), both install layouts resolving skills, loud failure when skills are missing, tool mapping sourced verbatim from hermes-tools.md, and a bootstrap-size guard against hermes' 10k-char context spill threshold. 19 tests, passing. Install docs collapse into the README section per maintainer direction: docs/README.hermes.md and .hermes-plugin/INSTALL.md are gone; the README carries the two-line install plus the compaction caveat. plugin.yaml version aligned to 6.1.1.
obra
marked this pull request as ready for review
July 24, 2026 00:44
|
Nice to see this being worked on! |
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.
Who is submitting this PR? (required)
claude-fable-5)What problem are you trying to solve?
Hermes Agent (NousResearch) users have no Superpowers support. Three community PRs attempted it (#1922, #1892, #1861 — plus closed slop #1972/#2021); #1922 was the best but its own acceptance transcript showed
brainstormingbeing skipped, and live testing in the superpowers-evals quorum harness proved why: itsctx.inject_message-from-on_session_startmechanism silently delivers nothing (the call returnsFalse). The bootstrap never reached the model, making the skills dead weight.What does this PR change?
Adds Hermes Agent harness support with a working, eval-verified bootstrap:
.hermes-plugin/(a Hermes plugin that injects theusing-superpowersbootstrap via the documentedpre_llm_call→{"context": …}path on the first turn, and registers every stock skill with Hermes' native loader soskill_view("superpowers:<name>")works — no per-harness skill copies),references/hermes-tools.md,tests/hermes/(19 tests against the real plugin contract, including install-layout resolution, Path-type fidelity forregister_skill, and a bootstrap-size guard under hermes' 10k-char context spill threshold), Platform Adaptation table row, and a two-line install in the main README (hermes plugins install obra/superpowers --enable+ restart note + compaction caveat) — no separate per-harness doc files, per maintainer direction.Hard-won implementation facts encoded in the plugin (all verified against the real CLI in a container):
on_session_startreturn values are ignored andctx.inject_messagerefuses from it (returnsFalse) —pre_llm_callis the working injection path.ctx.register_skillrequires apathlib.Path; astrraises inside hermes and silently disables the whole plugin — soregister()is kept failure-proof and path handling is explicit..hermes-plugin/andskills/as siblings; flattened) and fail loudly when absent instead of silently skipping.agent/conversation_loop.py+agent/turn_context.py): the hook fires before every LLM call; we return context only onis_first_turn. Hermes stamps the composed content onto that user message as a persistedapi_contentsidecar and replays it byte-identically on every later API call (its prompt-cache invariant), so one first-turn injection stays in model context for the whole session. Session exports show only the clean content, so verification must be behavioral — which the eval below is.drop_stale_api_content()discards the sidecar if compression rewrites the first user row — a long session that compacts over the first turn loses the bootstrap with no re-injection seam. Upstream feature request (post_compressionhook) is the clean fix; ECA (postCompact) and oh-my-pi (session_compact) both provide the equivalent.Is this change appropriate for the core library?
Yes — new harness support, the one category where new integration surface belongs in core. Stock skills untouched; one adaptation reference file per the established pattern (codex/pi/antigravity).
What alternatives did you consider?
on_session_start+inject_message): mechanism empirically dead; branch bundled ~14 files of v6.1.0 release drift.dist/hermes/, manual per-skill install, per-session opt-in): rejected — Superpowers ships one canonical skills tree, and the repo's harness rules require session-start bootstrap with no per-session opt-in.pre_llm_call— the right hook! — but targeting main, plugin files at repo root, and an extra behavioral "startup guard" injected into the tuned bootstrap): the hook choice is vindicated here; the bootstrap tampering is not carried.hermes skills tapinstead of a plugin: taps register skills but provide no session-start injection; the bootstrap is what makes skills auto-trigger, so a plugin is required regardless.Does this PR contain multiple unrelated changes?
No. Every file serves Hermes harness support.
Existing PRs
Environment tested
hermes versiongit install)z-ai/glm-5.2New harness support (required if this PR adds a new harness)
The integration loads the bootstrap at session start via the plugin's
pre_llm_callhook — no manual copying, no runtime shim, no per-session opt-in. Acceptance test run as a live quorum eval (superpowers-evalshermestarget, realhermesREPL driven over tmux in a container, isolated throwaway$HOME): deterministic checks pass —skill-called superpowers:brainstorming✓, skill-before-Write ✓, skill-before-Edit ✓. The same scenario against #1922's original mechanism fails all three (recorded RED baseline). Full campaign log: superpowers-evalsdocs/experiments/2026-07-23-hermes-target-bringup.md.Clean-session transcript for "Let's make a react todo list"
Evaluation
scenarios/superpowers-bootstrap(the acceptance test) against this branch in the eval container, plus targeted mechanism probes (hook firing, injection delivery,skill_viewresolution, both install layouts).skill_view("superpowers:brainstorming")returns the stock SKILL.md in both install layouts.Validation coverage and known gaps
$HOME(the quorum eval), both install layouts, unit suite 19/19.nousresearch/hermes-4-405bnor-70bexposes thetoolsparameter there, and the hermes CLI is tool-driven; every call 404s ("No endpoints found that support tool use"). Native Hermes-4 validation requires the Nous Portal API and a key; recorded as a documented negative result in the evals experiment log, to be run when a Nous credential exists.hermes plugins install obra/superpowersGitHub-clone flow can only be exercised once this lands on the default branch (the eval stages the plugin from a checkout); one manual smoke after merge closes that.Rigor
superpowers:writing-skillsand completed adversarial pressure testing — N/A as such: no tuned skill content is modified; the only skills/ change is addingreferences/hermes-tools.mdand one Platform Adaptation table row (the established per-harness pattern). The bootstrap is carried verbatim.Human review