diff --git a/AGENTS.md b/AGENTS.md index c92f644..5039f6c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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. diff --git a/README.md b/README.md index a3f4905..7a979d7 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/skills/hermes-plugins/SKILL.md b/skills/hermes-plugins/SKILL.md new file mode 100644 index 0000000..b3c0386 --- /dev/null +++ b/skills/hermes-plugins/SKILL.md @@ -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. diff --git a/skills/hermes-plugins/agents/openai.yaml b/skills/hermes-plugins/agents/openai.yaml new file mode 100644 index 0000000..b239234 --- /dev/null +++ b/skills/hermes-plugins/agents/openai.yaml @@ -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." diff --git a/skills/hermes-plugins/references/official-hermes-agent.md b/skills/hermes-plugins/references/official-hermes-agent.md new file mode 100644 index 0000000..900a3cd --- /dev/null +++ b/skills/hermes-plugins/references/official-hermes-agent.md @@ -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. diff --git a/skills/hermes-plugins/references/plugin-kit.md b/skills/hermes-plugins/references/plugin-kit.md new file mode 100644 index 0000000..100c8dd --- /dev/null +++ b/skills/hermes-plugins/references/plugin-kit.md @@ -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. diff --git a/skills/hermes-plugins/references/surface-checklist.md b/skills/hermes-plugins/references/surface-checklist.md new file mode 100644 index 0000000..20d8a8c --- /dev/null +++ b/skills/hermes-plugins/references/surface-checklist.md @@ -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.