Hermes.News

Technical news, guides and deep-dives on Hermes Agent by Nous Research


Core FeaturesSep 12, 2026807 words

Plugins: Extending Hermes With Custom Tools and Hooks

Hermes has a plugin system for adding custom tools, hooks, and integrations without modifying core code. If you want to create a custom tool for yourself, your team, or one project, this is usually the right path. The core idea is simple: drop a directory into ~/.hermes/plugins/ containing a plugin.yaml manifest and Python code, restart Hermes, and your tools appear alongside the built-in ones — the model can call them immediately.

Anatomy of a Plugin

A minimal plugin is just two or three files:

~/.hermes/plugins/hello-world/
├── plugin.yaml      # manifest: name, version, description
├── __init__.py      # register() — wires schemas to handlers
└── tools.py         # tool handlers (what runs when called)

Inside register(ctx), you use the ctx.* API to add capabilities: ctx.register_tool() adds a tool the LLM can call, ctx.register_hook() registers a lifecycle hook like post_tool_call, ctx.register_command() adds a /name slash command, and ctx.register_cli_command() adds a hermes <plugin> <subcommand> entry. You can also inject messages into conversations, ship data files, bundle skills (namespaced as plugin:skill), and register gateway platforms, image/video/context engines, approval transports, and memory backends.

Discovery and the Opt-In Allowlist

Plugins are found from several sources: bundled plugins ship with Hermes; user plugins live in ~/.hermes/plugins/; project plugins live in .hermes/plugins/ (disabled by default, enabled only for trusted repos via HERMES_ENABLE_PROJECT_PLUGINS=true); and distributed pip packages register through hermes_agent.plugins entry points, with a NixOS declarative path available too.

Plugins are opt-in by default (with a few exceptions). Discovery finds them, but nothing with hooks or tools loads until you add the plugin's name to plugins.enabled in ~/.hermes/config.yaml. This stops third-party code from running without your explicit consent. Manage it with hermes plugins, hermes plugins enable <name>, and hermes plugins disable <name>. Bundled platform and backend plugins (like IRC or Teams channel adapters) bypass the gate because they're part of Hermes' built-in surface — the actual channel turns on via its own gateway.platforms.<name>.enabled setting.

Types of Plugins

Hermes has four kinds of plugins:

  • General plugins — add tools, hooks, slash commands, and CLI commands; multi-select via enable/disable.
  • Memory providers — replace or augment built-in memory; single-select (one active).
  • Context engines — replace the built-in context compressor; single-select.
  • Model providers — declare an inference backend; many load, the user picks one at a time via --provider or config.yaml.

Not everything is a Python plugin. Some extension surfaces intentionally use config-driven shell commands (TTS, STT, shell hooks), external MCP servers the agent connects to, or drop-in directories with their own manifest format.

Capabilities, Consent, and Pinning

Plugins can declare the privileged host surfaces they want in their plugin.yaml — for example tools.override to replace built-in tools, or llm.model_override. When a plugin declares capabilities, install and enable show the list with one-line risk descriptions and ask once; granting records it under plugins.entries.<id>.granted_capabilities with a consent hash. A plugin update can never silently widen its access — new capabilities stay off until you consent. Note that capabilities are a consent and audit layer, not a sandbox: plugins run as regular in-process Python, so a malicious plugin can ignore every gate. Granting a capability is a statement of trust in the plugin author, and you should only install plugins from sources you trust.

To keep your stack reproducible, hermes plugins install owner/repo --ref <40-char-commit> pins a plugin to an exact commit; hermes plugins update refuses to move a pinned plugin. The curated plugin catalog (hermes plugins search <term>, hermes plugins browse) resolves bare names to SHA-pinned repositories. Plugin packs (hermes-pack.yaml) let you share a set of pinned plugins declaratively, and install goes through the same pinned path as a direct install — with no bulk consent.

Security Scanning and Using Plugins

Every hermes plugins install and update runs a static security scan over the plugin tree before it is activated, reusing the same threat-pattern engine as the Skills Hub guard — catching exfiltration of credential stores, reverse shells, destructive commands, and prompt injection. The verdict is one of three: safe (installs normally), caution (findings shown, confirm to continue), or dangerous (blocked, and --force does not override). After install, plugins can reach MCP servers through ctx.call_mcp(), but only for servers explicitly listed in the per-plugin mcp_allowlist (off by default). The unified interactive UI — hermes plugins with no arguments — shows general plugins as checkboxes and provider plugins as radio pickers, and /plugins shows what's loaded in a running session.

Key Takeaways

  • Plugins add custom tools, hooks, slash commands, and integrations without modifying core code.
  • Install is a drop-in directory — plugin.yaml plus Python — and plugins are opt-in via plugins.enabled.
  • Four plugin kinds cover general tools, memory providers, context engines, and model providers.
  • Capabilities + consent control privileged access, and commits can be SHA-pinned for reproducibility.
  • Every install is scanned for threats, with dangerous verdicts always blocked.