From fb903b8f08c8c9df2b4d8e0175d50eb888de62f8 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 15 Apr 2026 19:55:25 -0700 Subject: [PATCH] docs: document register_command() for plugin slash commands (#10671) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: implement register_command() on plugin context Complete the half-built plugin slash command system. The dispatch code in cli.py and gateway/run.py already called get_plugin_command_handler() but the registration side was never implemented. Changes: - Add register_command() to PluginContext — stores handler, description, and plugin name; normalizes names; rejects conflicts with built-in commands - Add _plugin_commands dict to PluginManager - Add commands_registered tracking on LoadedPlugin - Add get_plugin_command_handler() and get_plugin_commands() module-level convenience functions - Fix commands.py to use actual plugin description in Telegram bot menu (was hardcoded 'Plugin command') - Add plugin commands to SlashCommandCompleter autocomplete - Show command count in /plugins display - 12 new tests covering registration, conflict detection, normalization, handler dispatch, and introspection Closes #10495 * docs: add register_command() to plugin guides - Build a Plugin guide: new 'Register slash commands' section with full API reference, comparison table vs register_cli_command(), sync/async examples, and conflict protection docs - Features/Plugins page: add slash commands to capabilities table and plugin types summary --- website/docs/guides/build-a-hermes-plugin.md | 53 +++++++++++++++++++- website/docs/user-guide/features/plugins.md | 3 +- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/website/docs/guides/build-a-hermes-plugin.md b/website/docs/guides/build-a-hermes-plugin.md index aed218ff8e..e8611197a1 100644 --- a/website/docs/guides/build-a-hermes-plugin.md +++ b/website/docs/guides/build-a-hermes-plugin.md @@ -561,8 +561,59 @@ After registration, users can run `hermes my-plugin status`, `hermes my-plugin c **Active-provider gating:** Memory plugin CLI commands only appear when their provider is the active `memory.provider` in config. If a user hasn't set up your provider, your CLI commands won't clutter the help output. +### Register slash commands + +Plugins can register in-session slash commands — commands users type during a conversation (like `/lcm status` or `/ping`). These work in both CLI and gateway (Telegram, Discord, etc.). + +```python +def _handle_status(raw_args: str) -> str: + """Handler for /mystatus — called with everything after the command name.""" + if raw_args.strip() == "help": + return "Usage: /mystatus [help|check]" + return "Plugin status: all systems nominal" + +def register(ctx): + ctx.register_command( + "mystatus", + handler=_handle_status, + description="Show plugin status", + ) +``` + +After registration, users can type `/mystatus` in any session. The command appears in autocomplete, `/help` output, and the Telegram bot menu. + +**Signature:** `ctx.register_command(name: str, handler: Callable, description: str = "")` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `name` | `str` | Command name without the leading slash (e.g. `"lcm"`, `"mystatus"`) | +| `handler` | `Callable[[str], str \| None]` | Called with the raw argument string. May also be `async`. | +| `description` | `str` | Shown in `/help`, autocomplete, and Telegram bot menu | + +**Key differences from `register_cli_command()`:** + +| | `register_command()` | `register_cli_command()` | +|---|---|---| +| Invoked as | `/name` in a session | `hermes name` in a terminal | +| Where it works | CLI sessions, Telegram, Discord, etc. | Terminal only | +| Handler receives | Raw args string | argparse `Namespace` | +| Use case | Diagnostics, status, quick actions | Complex subcommand trees, setup wizards | + +**Conflict protection:** If a plugin tries to register a name that conflicts with a built-in command (`help`, `model`, `new`, etc.), the registration is silently rejected with a log warning. Built-in commands always take precedence. + +**Async handlers:** The gateway dispatch automatically detects and awaits async handlers, so you can use either sync or async functions: + +```python +async def _handle_check(raw_args: str) -> str: + result = await some_async_operation() + return f"Check result: {result}" + +def register(ctx): + ctx.register_command("check", handler=_handle_check, description="Run async check") +``` + :::tip -This guide covers **general plugins** (tools, hooks, CLI commands). For specialized plugin types, see: +This guide covers **general plugins** (tools, hooks, slash commands, CLI commands). For specialized plugin types, see: - [Memory Provider Plugins](/docs/developer-guide/memory-provider-plugin) — cross-session knowledge backends - [Context Engine Plugins](/docs/developer-guide/context-engine-plugin) — alternative context management strategies ::: diff --git a/website/docs/user-guide/features/plugins.md b/website/docs/user-guide/features/plugins.md index e5e99a463a..bcc927bb49 100644 --- a/website/docs/user-guide/features/plugins.md +++ b/website/docs/user-guide/features/plugins.md @@ -83,6 +83,7 @@ Project-local plugins under `./.hermes/plugins/` are disabled by default. Enable |-----------|-----| | Add tools | `ctx.register_tool(name, schema, handler)` | | Add hooks | `ctx.register_hook("post_tool_call", callback)` | +| Add slash commands | `ctx.register_command(name, handler, description)` — adds `/name` in CLI and gateway sessions | | Add CLI commands | `ctx.register_cli_command(name, help, setup_fn, handler_fn)` — adds `hermes ` | | Inject messages | `ctx.inject_message(content, role="user")` — see [Injecting Messages](#injecting-messages) | | Ship data files | `Path(__file__).parent / "data" / "file.yaml"` | @@ -117,7 +118,7 @@ Hermes has three kinds of plugins: | Type | What it does | Selection | Location | |------|-------------|-----------|----------| -| **General plugins** | Add tools, hooks, CLI commands | Multi-select (enable/disable) | `~/.hermes/plugins/` | +| **General plugins** | Add tools, hooks, slash commands, CLI commands | Multi-select (enable/disable) | `~/.hermes/plugins/` | | **Memory providers** | Replace or augment built-in memory | Single-select (one active) | `plugins/memory/` | | **Context engines** | Replace the built-in context compressor | Single-select (one active) | `plugins/context_engine/` |