Extend hermes without forking
Deterministic Agent Skill: extend or override Hermes runtime behavior via plugins/config/skills/env — without forking the deployed package.
npx -y skills add srinitude/extend-hermes-without-forkingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Extend or override Hermes runtime behavior using the supported plugin, config, skill, and env layers in ~/.hermes — never by editing the Nous-deployed package. Use when the user says "extend Hermes", "add a Hermes plugin", "override Hermes behavior", "add a slash command", "add a hermes CLI subcommand", "hook a tool call", "customize Hermes without forking", or "change Hermes without touching the package", even if they do not say "plugin" explicitly. Do NOT use for claude-code (Anthropic's claude CLI delegation), hermes-config-management (pure config.yaml audits), hermes-skill-operations (installing/updating skill packages), or hermes-tui-customization (TUI chrome) tasks.
The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
10.3 KB, as published. Nobody here has run it
Extend Hermes without forking
Hermes is built so all customization lives OUTSIDE the deployed package, in
~/.hermes/ and config. You override behavior by LAYERING, not by patching
files Nous ships. This skill names the five supported surfaces and gives one
default path for the most common job: adding a plugin that registers a hook,
tool, slash command, or CLI subcommand.
CRITICAL RULES
- NEVER edit files under the deployed package (
~/.hermes/hermes-agent/). All changes go in~/.hermes/plugins/,~/.hermes/skills/,config.yaml, or environment variables. Package edits are lost on upgrade. - A user plugin at
~/.hermes/plugins/<name>/with the SAME name as a bundled plugin REPLACES it. This is the override mechanism — use it, do not fork. - Built-in slash commands (
/model,/help,/cost, etc.) CANNOT be overridden by a plugin.register_command()rejects any name thatresolve_command()resolves. To change built-in behavior, influence its INPUTS (config, caches, env), not its handler. - Plugins are opt-in. A new user plugin does nothing until its directory name
is in
plugins.enabled. Enable withhermes plugins enable <name>— never hand-editconfig.yaml(it is a protected file). config.yamlis write-protected. Usehermes plugins enable/disableandhermes configcommands; do not write the file directly.- Verify every claim against source before reporting. Use the exact commands in the Ordered workflow; do not rely on memory of the API shape.
- Offload counting, frontmatter checks, and plugin-shape validation to the
scripts in
scripts/; do not eyeball them. - If a required fact is missing (target surface, plugin name, hook name),
output
INSUFFICIENT CONTEXT: <field>and stop instead of guessing.
Gotchas
- Editing
~/.hermes/hermes-agent/to change behavior: WRONG. Drop a same-named plugin in~/.hermes/plugins/instead. - Expecting
register_command("model", ...)to replace/model: it is silently skipped (built-in collision). Use a NEW command name, or change the built-in's inputs. - Plugin written but "nothing happens": the directory name is not in
plugins.enabled. Runhermes plugins enable <name>and start a new session. - Hand-editing
config.yaml: blocked as a protected file. Use the CLI. register(ctx)that registers nothing: a plugin must call at least onectx.register_*method to have any effect.pre_llm_callreturning{"messages": ...}: wrong shape. It returns{"context": text}. Read the live hook contract before writing one.- Confusing the term "skill" (procedural markdown in
~/.hermes/skills/) with "plugin" (executable code in~/.hermes/plugins/). One term per concept: PLUGIN = code, SKILL = procedure, CONFIG =config.yaml.
The five extension surfaces
- PLUGIN — executable Python in
~/.hermes/plugins/<name>/(plugin.yaml+__init__.pywithregister(ctx)). Registers hooks, tools, slash commands, CLI subcommands, context engines, and backends. - CONFIG — the Hermes
config.yaml(in~/.hermes/) selects providers, models, and which plugins load (plugins.enabled/plugins.disabled). Edited via the CLI. - SKILL — procedural markdown in
~/.hermes/skills/<name>/SKILL.md. Overlays how a task is done; no executable override of the runtime. To author a new skill deterministically (so weak models can execute it) and validate it against Hermes, use thebuilding-deterministic-skillsskill — its methodology, skeleton, and validators. Repo: https://github.com/srinitude/building-deterministic-skills (install:hermes skills install srinitude/building-deterministic-skills/. --yes). - ENV VARS — flip behaviors at startup (e.g.
HERMES_BUNDLED_PLUGINS,HERMES_ENABLE_PROJECT_PLUGINS,HERMES_PLUGINS_DEBUG). - ENTRY-POINT PIP PLUGIN — a pip package exposing the
hermes_agent.pluginsentry-point group; sameregister(ctx)contract.
Read references/extension-surfaces.md ONLY when you need the source-grounded
detail (file:line citations, full VALID_HOOKS list, register_* signatures,
hook return-value contracts).
PluginContext API (the register surface)
A plugin's register(ctx) calls these. Read
references/extension-surfaces.md before using one you have not used before.
ctx.register_hook(name, callback)— run code at a lifecycle point. Valid names are inVALID_HOOKS(see reference).ctx.register_tool(...)— add a model-callable tool.ctx.register_command(name, handler, description, args_hint)— add an in-session slash command (/<name>). Built-in collisions are rejected.ctx.register_cli_command(name, help, setup_fn, handler_fn, description)— add ahermes <name>terminal subcommand.ctx.register_context_engine(engine)— replace the built-in compressor.ctx.register_image_gen_provider(...)/register_dashboard_auth_provider(...)— pluggable backends.
Ordered workflow
Default path: create one enabled user plugin in ~/.hermes/plugins/, validate
it, and confirm it loads. Progress:
- Confirm the target surface is a PLUGIN. If the user wants config-only edits, stop and defer to hermes-config-management; if skill packages, defer to hermes-skill-operations.
- If the plugin name, target hook, or command name is missing, output
INSUFFICIENT CONTEXT: <field>and stop. - Locate the package source root:
ls -d ~/.hermes/hermes-agent/hermes_cli/plugins.py. - Read the live API you will use:
search_filesfordef register_command/def register_cli_command/VALID_HOOKSin~/.hermes/hermes-agent/hermes_cli/plugins.py. - Pick the plugin directory name (lowercase, hyphens). This name is both the
directory and the
plugins.enabledkey. - Copy the skeleton:
cp -r assets/plugin-skeleton ~/.hermes/plugins/<name>then rename placeholders to<name>inside both files. - Write
plugin.yamlwithnameequal to the directory name. - Write
__init__.pywith aregister(ctx)that calls at least onectx.register_*method. - For a slash command, confirm the name does NOT collide with a built-in:
search_filesfor the name inhermes_cli/commands.pyCOMMAND_REGISTRY; if it resolves, choose a different name. - Validate the plugin shape:
python3 scripts/validate-hermes-plugin.py ~/.hermes/plugins/<name>. - Enable it:
hermes plugins enable <name>. - Confirm discovery:
hermes plugins listshows<name>asenabled. - Exercise it: run the new
hermes <name>subcommand, or trigger the hook, and capture real output. Do not report success without it. - Run the full Validation pipeline below and fix every failure before returning.
Validation pipeline
- Frontmatter:
python3 scripts/check-skill-frontmatter.py - Readability:
python3 scripts/check-dumb-model-readability.py SKILL.md - No dead links:
python3 scripts/check-no-dead-links.py - Determinism:
python3 scripts/check-determinism.py - Plugin shape (functional):
python3 scripts/validate-hermes-plugin.py assets/plugin-skeleton - Hermes security scan + discovery: import
tools.skills_guard.scan_skillwithsource='agent-created'and requiretools.skills_guard.should_allow_install(result)returnsTrue; importagent.skill_utils.get_all_skills_dirsand confirm the skill path is found. - Hermes pytest gate:
cd /Users/kiren/.hermes/hermes-agent && ./venv/bin/python -m pytest tests/tools/test_skill_manager_tool.py tests/tools/test_skill_size_limits.py tests/agent/test_skill_utils.py tests/tools/test_skills_guard.py -q
Output template
Surface: PLUGIN | CONFIG | SKILL | ENTRYPOINT | ENV
Plugin name:
Registered: <hook|tool|command|cli_command|backend>
Enabled: <yes via `hermes plugins enable <name>` | n/a>
Evidence: <hermes plugins list line + real command output>
Validation: <each pipeline command + PASS/FAIL>
Package edited: NO
INSUFFICIENT CONTEXT escape hatch
If any of these are unknown, emit INSUFFICIENT CONTEXT: <field> and stop:
the extension surface, the plugin directory name, the hook name (for a hook),
or the slash/CLI command name (for a command). Do not invent an API shape.
Critical-rule placement note
These critical rules are intentionally front-loaded at the top of this file and book-ended: the final self-check below repeats the load-bearing ones so a weak model re-reads them before finishing.
Verification checklist
- No file under
~/.hermes/hermes-agent/was edited (package untouched). - The plugin lives in
~/.hermes/plugins/<name>/withplugin.yaml+__init__.pyand aregister(ctx)that calls actx.register_*method. - No slash command name collides with a built-in (
resolve_command). -
hermes plugins enable <name>was run andhermes plugins listshows it enabled. - The new command/hook was exercised and real output was captured.
-
scripts/check-skill-frontmatter.pypasses. -
scripts/check-dumb-model-readability.py SKILL.mdpasses. -
scripts/check-no-dead-links.pypasses. -
scripts/check-determinism.pypasses. -
scripts/validate-hermes-plugin.py assets/plugin-skeletonpasses. -
tools.skills_guard.scan_skill(source='agent-created')returnsallowed=Trueviashould_allow_install. - The Hermes pytest gate passes.
- Critical rules stayed front-loaded and book-ended.