Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,6 @@ plugin.

When changing conventions or exported helpers, update `README.md` examples and
tests together so consuming Hermes plugins have a reliable migration path.
Keep `skills/hermes-plugins/references/plugin-kit.md` aligned with public API
and contract changes so the repo-owned authoring skill does not teach stale
behavior.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,18 @@ and `send_voice` with the expected files, without separate text messages. It
also runs the kit-owned spoiler extension against Hermes' real config, session,
async bridge, and Telegram library shapes while mocking only Bot network calls.

## Agent skill

The repo owns a Hermes plugin authoring skill at
[`skills/hermes-plugins`](skills/hermes-plugins). It includes a kit API map,
surface checklist, and routed references to the official Hermes Agent docs.

To use this checkout as the canonical Codex skill:

```bash
ln -s "$(pwd)/skills/hermes-plugins" ~/.codex/skills/hermes-plugins
```

## Logging contract

The kit logs under the decorated handler's module logger, so each plugin can
Expand Down
100 changes: 100 additions & 0 deletions skills/hermes-plugins/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
name: hermes-plugins
description: Build, modify, migrate, review, and debug Hermes Agent plugin repositories. Use for plugin.yaml manifests, PluginContext or register(ctx), hermes-plugin-kit adoption, tools, commands, middleware, hooks, bundled skills, guarded host calls, media delivery, registration tests, and runtime toolset exposure. Do not use for Hermes core tools or specialized provider plugins unless the request explicitly targets those upstream surfaces.
version: 0.2.0
license: MIT
category: Development Workflow
metadata:
audience: developers
keywords: hermes-agent, plugins, hermes-plugin-kit, PluginContext
---

# Hermes Plugins

Work from the Hermes runtime contract outward. `hermes-plugin-kit` removes
repeated lifecycle boilerplate, but it does not replace Hermes Agent's plugin
API or make every extension type a general plugin.

## Load The Right Reference

- Read [references/plugin-kit.md](references/plugin-kit.md) before adopting,
upgrading, or debugging `hermes-plugin-kit`.
- Read [references/official-hermes-agent.md](references/official-hermes-agent.md)
for upstream plugin types, hooks, discovery, enablement, toolsets, or runtime behavior.
- Read [references/surface-checklist.md](references/surface-checklist.md) when
adding, removing, renaming, or auditing a declared plugin surface.

If these references disagree with the pinned or deployed Hermes source, the
source and effective runtime configuration win.

## First Pass

1. Read the repo's `AGENTS.md` or equivalent local guidance before editing.
2. Classify the extension: general plugin, platform, memory provider, context
engine, model provider, or another specialized backend. Do not force a
specialized interface through the kit.
3. Inspect `plugin.yaml`, `__init__.py`, and the actual `register(ctx)` path.
4. Check `pyproject.toml` and its lockfile to prove whether the kit is installed.
5. Inspect registration, parity, handler, privacy, and upstream-contract tests.
6. For live exposure, verify enabled plugins, effective toolsets, platform
allowlists, and the loaded tool inventory instead of trusting docs.

## Add Or Change A Surface

Update every declaration in one change set:

- Handler and schema or kit declaration.
- `register(ctx)` wiring, whether direct or through `register_plugin`.
- `plugin.yaml` exposure, requirements, version, and metadata.
- Registration, schema, auth, privacy, and manifest-parity tests.
- `AGENTS.md`, README, and runtime configuration when they enumerate the surface.

Treat `plugin.yaml` as a runtime/discovery contract, not generated documentation. If it disagrees with `register(ctx)`, the change is incomplete.

## Kit Boundaries

- Prefer `@tool` plus `register_all` for an existing tool-only plugin.
- Prefer `@command`, `@tool`, `@middleware`, `@hook`, `plugin_skill`, and
`register_plugin` for a full lifecycle plugin.
- Use direct `PluginContext` APIs for surfaces the kit does not wrap.
- Use `invoke_host_tool` or `deliver_media` for supported host-managed calls.
Do not dispatch `send_message` through `tools.registry`.
- Keep the kit dependency and lockfile current with the repo-native install command.

## Auth, Privacy, And Runtime Boundaries

Keep read-only tools usable without write credentials. Put mutations behind the
plugin's established auth and audit mechanism, then assert that in tests.

For Discord/community-facing plugins, check privacy boundaries before widening any response or memory surface. Prefer transcript/runtime evidence over plausible docs when exposing user, channel, memory, or bot-write behavior.

For catalog or content plugins, keep public summaries from leaking raw prompts, raw descriptions, raw lyrics, aligned lyric data, private memory, or internal classifier notes unless the user explicitly requests a permitted raw surface and the repo already supports it.

## Validation

Run the repo-native install/test commands before committing. Common examples:

```bash
make install
make test
make build
python -m unittest discover -s tests
```

Also run focused registration, manifest-parity, hook or middleware, and local
import tests for the surface touched. When compatibility matters, run contract
tests against the real pinned Hermes Agent checkout.

For tool surfaces, prefer a test that asserts every registered tool has:
matching `plugin.yaml` exposure, matching schema `name`, non-empty schema
`description`, object-shaped schema `parameters`, and a callable handler.

Before finalizing, re-run a quick inventory:

```bash
rg -n "register_tool|register_hook|register_command|register_skill|provides_tools|provides_hooks|provides_skills|requires_env" __init__.py plugin.yaml tests
```

## Shipping

If the user asks to ship, commit after validation. If the plugin is deployed through infra/GitOps, do not assume the repo change is live; verify the relevant deployment path, branch, tag, or rendered Hermes config when the user asks about runtime truth.
4 changes: 4 additions & 0 deletions skills/hermes-plugins/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Hermes Plugins"
short_description: "Build and verify Hermes Agent plugins"
default_prompt: "Use $hermes-plugins to build or audit a Hermes Agent plugin against hermes-plugin-kit and the official upstream contracts."
88 changes: 88 additions & 0 deletions skills/hermes-plugins/references/official-hermes-agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Official Hermes Agent References

Use these upstream references for Hermes runtime behavior. The official docs
describe the direct `PluginContext` API; `hermes-plugin-kit` is a consumer-side
adapter that removes repeated boilerplate around part of that API.

## Primary Documentation

- [Build a Hermes Plugin](https://hermes-agent.nousresearch.com/docs/developer-guide/plugins)
covers manifests, schemas, handlers, `register(ctx)`, hooks, skills, testing,
packaging, and installation for general plugins.
- [Plugins](https://hermes-agent.nousresearch.com/docs/user-guide/features/plugins)
covers extension types, discovery sources, enablement, capability routing,
and the current `PluginContext` surface.
- [Event Hooks](https://hermes-agent.nousresearch.com/docs/user-guide/features/hooks)
covers valid hook names, callback shapes, blocking and context injection,
lifecycle timing, shell hooks, and gateway hooks.
- [Skills System](https://hermes-agent.nousresearch.com/docs/user-guide/features/skills)
covers skill layout, namespacing, external directories, platform controls,
and bundles.
- [CLI Commands Reference](https://hermes-agent.nousresearch.com/docs/reference/cli-commands)
covers `hermes plugins`, `hermes tools`, update, and runtime inspection commands.
- [Toolsets Reference](https://hermes-agent.nousresearch.com/docs/reference/toolsets-reference)
explains how tool bundles control availability per platform, session, and task.
- [Adding Tools](https://hermes-agent.nousresearch.com/docs/developer-guide/adding-tools)
is for built-in core tools. Use it only when the request explicitly targets
Hermes Agent core rather than a standalone plugin.
- [Hermes Agent repository guidance](https://github.com/NousResearch/hermes-agent/blob/main/AGENTS.md)
records upstream contribution policy and the boundary between core and plugins.

When a website page and `main` source differ, inspect the official repository
page linked from the documentation and the exact revision the target runtime pins.

## Choose The Correct Extension Type

General plugins cover tools, lifecycle hooks, session slash commands, CLI
subcommands, bundled skills, message injection, and host-owned LLM access.

Specialized interfaces have separate discovery and activation contracts:

- Platform adapters for gateway channels.
- Memory providers.
- Context engines.
- Model providers.
- Image, video, browser, web-search, and secret-source providers.
- Desktop and dashboard extensions.

Do not route a specialized provider through `register_tool` merely because the
kit makes tools convenient.

## Runtime Authority Order

1. The deployed or pinned Hermes Agent source and effective configuration.
2. Official docs for the matching version.
3. `hermes-plugin-kit` contract tests against that source.
4. The plugin's checked-in docs and local fake-context tests.

For mutable runtime questions, verify plugin enablement, the loaded revision,
effective toolsets, platform-specific allowlists, and the actual tool inventory.
Discovery alone does not prove a plugin is enabled or exposed on a platform.

## Source Seams To Verify

From a Hermes Agent checkout, locate contracts instead of guessing paths from
memory:

```bash
rg -n "class PluginContext|def register_tool|def register_hook|def register_command|def register_skill" hermes_cli
rg -n "VALID_HOOKS|VALID_MIDDLEWARE|register_middleware" hermes_cli agent
rg -n "class ToolRegistry|def dispatch|def get_definitions" tools
rg -n "send_message|MEDIA:|audio_as_voice|as_document" tools gateway hermes_cli
```

The common high-value seams are the plugin context/manager, middleware
dispatcher, tool registry, agent-loop hook call sites, and gateway message
formatters. Paths move faster than the concepts, so search the pinned checkout.

## Reconcile Direct Docs With The Kit

Official examples usually hand-write schemas, catch exceptions, and return JSON
strings. With `@tool`, the kit builds the schema, validates required arguments,
wraps exceptions, logs safely, and encodes dict results. Preserve the upstream
wire contract without duplicating that boilerplate inside the handler.

Official `ctx.register_*` methods remain the source contract. The kit's
`tests/test_hermes_contract.py` should bind its generated calls to the real
signatures and exercise the real registry or gateway seam while mocking only
the final network client.
100 changes: 100 additions & 0 deletions skills/hermes-plugins/references/plugin-kit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# hermes-plugin-kit Reference

Use this reference when a general Hermes plugin consumes or changes
`hermes-plugin-kit`. The kit is an installable helper package, not a
path-loaded Hermes plugin and not an upstream Hermes API.

## Canonical Local Sources

- Public guide and examples: [`README.md`](../../../README.md)
- Maintainer rules: [`AGENTS.md`](../../../AGENTS.md)
- Exported API and behavior: [`hermes_plugin_kit/__init__.py`](../../../hermes_plugin_kit/__init__.py)
- Unit contracts: [`tests/test_kit.py`](../../../tests/test_kit.py)
- Real Hermes compatibility contracts:
[`tests/test_hermes_contract.py`](../../../tests/test_hermes_contract.py)
- Package and Python requirements: [`pyproject.toml`](../../../pyproject.toml)

Read the source and tests when exact signatures matter. This page is routing
guidance, not a second implementation specification.

## Surface Map

| Plugin need | Kit API | Registration | Important contract |
| --- | --- | --- | --- |
| LLM tool | `@tool`, `tool_name`, argument helpers | `register_all` or `register_plugin` | Handler accepts `(args, **kwargs)` and may return a dict, raise, or deliberately return an encoded string. |
| Session slash command | `@command` | `register_plugin` | Name is bare lowercase kebab-case; handler receives raw trailing text and may be sync or async. |
| Request or execution middleware | `@middleware`, `MiddlewareKind` | `register_plugin` | Callback is synchronous; request phases replace payloads, execution phases call single-use `next_call`. |
| Lifecycle hook | `@hook` | `register_plugin` | Hermes kwargs and return values pass through; exceptions are re-raised for Hermes isolation. |
| Plugin-owned skill | `plugin_skill` | `register_plugin(..., skills=...)` | Hermes adds the plugin namespace; missing required skills fail, optional skills warn and skip. |
| Host-managed call | `invoke_host_tool` | None | Use for supported non-registry capabilities such as `send_message`; pre/post-tool hooks remain active. |
| Local media delivery | `MediaPayload`, `MediaType`, `deliver_media` | Consumer registers suppression hooks | File must be absolute, present, and non-empty; `origin` resolves from task-local Hermes context. |

`RegistrationSummary` reports commands, tools, middleware, hooks, skills, and
skipped optional skills registered by `register_plugin`.

## What The Kit Owns

- Tool naming and the `function.parameters` schema shape.
- Required-argument metadata, validation, and model-facing error text.
- JSON success and error envelopes around kit-decorated tool handlers.
- Redacted lifecycle logging and registration inventories.
- Duplicate lifecycle declaration checks before registration.
- Guarded host invocation for supported host-managed tools.
- Typed Hermes media directives, origin resolution, privacy-safe results, and
the narrow Telegram spoiler-photo extension.

## What It Does Not Own

Use the direct Hermes API or the specialized upstream plugin interface for:

- `ctx.register_cli_command`, `ctx.dispatch_tool`, `ctx.inject_message`, or
`ctx.llm.complete*`.
- Gateway platform adapters.
- Memory, context-engine, model, image, video, browser, web-search, secret
source, desktop, or dashboard provider interfaces.
- Plugin discovery, enablement, platform toolset selection, or core agent-loop behavior.

Do not add a kit abstraction merely to hide one direct `PluginContext` call.
Expand the kit when there is a repeated convention or a failure mode worth
making structurally impossible.

## Consumer Migration

1. Prove the current registration and dependency state from code and
`pyproject.toml`, not README claims.
2. Add `hermes-plugin-kit` through the consumer's package workflow, then refresh
its lockfile with the repo-native install command.
3. Wrap existing handlers without changing business behavior.
4. Use `register_all` for tool-only migration or `register_plugin` when adopting
commands, middleware, hooks, or plugin skills.
5. Keep `plugin.yaml`, auth gates, toolsets, docs, and registration tests in parity.
6. Run the consumer suite and a real Hermes contract test when runtime APIs matter.

## Failure Traps

- A top-level JSON Schema `properties` field makes the model see empty arguments.
- Hermes tool names share a global registry. Use `tool_name(namespace, verb, noun)`
and avoid core agent-loop names and the reserved `memory_` prefix.
- Plain Hermes handlers return encoded strings. Kit-decorated handlers may return
dictionaries because the wrapper encodes them. Do not double-encode by habit.
- `send_message` is host-managed, not guaranteed to be registry-backed.
- A successful `deliver_media` call needs
`transform_media_delivery_output` registered as `transform_llm_output` and
`clear_media_delivery_state` registered as `on_session_end`, or the gateway
can emit duplicate final output.
- The kit follows the real Hermes contract tests. A fake context alone can hide
signature drift.

## Validation

In this repository:

```bash
make install
make test
make build
```

In a consumer, run its native suite plus registration and manifest-parity tests.
Point contract tests at a real checkout with `HERMES_AGENT_PATH` when automatic
checkout discovery is not appropriate.
64 changes: 64 additions & 0 deletions skills/hermes-plugins/references/surface-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Hermes Plugin Surface Checklist

Use this checklist when adding, renaming, removing, reviewing, or debugging Hermes plugin exposure.

## Required Inventory

- `__init__.py`: `register(ctx)`, direct `ctx.register_*` calls,
`register_all`, `register_plugin`, and imported decorated declarations.
- `plugin.yaml`: supported `provides_*` fields, `requires_env`, description,
version, kind, and plugin metadata.
- `tools.py` or equivalent: handler behavior and API/client calls.
- `schemas.py` or kit declarations: JSON schema names, descriptions, required
fields, enums, defaults, toolsets, and environment gates.
- Lifecycle modules: `@command`, `@middleware`, `@hook`, direct registration,
callback contracts, and failure tolerance.
- `skills/**/SKILL.md`: bundled Hermes skills that may be conditionally registered.
- `tests/**`: registration counts, manifest parity, schema/tool definition
parity, lifecycle signatures, auth requirements, handler behavior, and privacy boundaries.
- `AGENTS.md` or repo docs: public surface inventory and validation commands.

## Surface Change Rules

- Keep toolset names consistent with repo preference. In `hermes-plugin-dsl`, new tools stay in the `dsl` toolset unless the user explicitly asks otherwise.
- When the repo uses `hermes-plugin-kit`, prefer `register_all` for tool-only
plugins and `register_plugin` for commands, tools, middleware, hooks, and skills.
- Add read-only tools without write-auth requirements.
- Add mutating tools to the repo's write-auth set and audit hooks when applicable.
- Register hooks in code and declare them in `plugin.yaml`.
- Register commands in code and update tests/docs if commands are part of the declared surface.
- Register middleware in code, test its exact phase contract against Hermes,
and do not invent unsupported manifest fields for it.
- Register bundled skills only through the repo's intended feature/config gates, and declare them in `plugin.yaml` if the manifest advertises skills.
- Update public surface counts in `AGENTS.md` when counts are listed.
- Add or maintain an exposure test that compares registered tool names with
`plugin.yaml` `provides_tools`, then checks each tool has a matching schema
name, non-empty description, object `parameters`, and callable handler.

## Common Failure Modes

- Handler exists but is missing from `_TOOLS` or `register(ctx)`.
- Registration exists but schema is missing or stale.
- Schema exists but `schema["name"]` disagrees with the registered tool name.
- Code registration changed but `plugin.yaml` still advertises the old surface.
- `plugin.yaml` advertises a tool/hook/skill that code no longer registers.
- A decorated kit declaration exists but the module passed to `register_all` or
`register_plugin` does not expose it.
- Middleware was treated as an observational hook or omitted its single-use
`next_call` contract.
- Mutating tool is usable without auth or is omitted from audit logging.
- Read-only tool incorrectly requires bot auth.
- Tests assert the old registration count but not the new contract.
- Docs say a hook exists after it was removed, or omit a hook that still runs.
- Runtime config enables/disables a plugin differently than the checked-in repo suggests.

## Runtime Truth

For questions about what Hermes actually exposes, inspect runtime state when available:

- Effective Hermes config for plugin repos, enabled toolsets, platform-specific config, and skill directories.
- The live tool list for the target platform, when the Hermes CLI/runtime is available.
- Rendered Kubernetes/Helm/Argo manifests for minilab or production deployments.
- Logs or pod files only after checking the effective config path that loads the plugin.

Checked-in docs are useful orientation, but runtime exposure is determined by the deployed plugin revision plus the active Hermes config.