Compare commits

...

1 Commits

Author SHA1 Message Date
Teknium
f9596c6a6f docs: update honcho CLI reference + document plugin CLI registration
Post PR #5295 docs audit — 4 fixes:

1. cli-commands.md: Update hermes honcho subcommand table with 4
   missing commands (peers, enable, disable, sync), --target-profile
   flag, --all on status, correct mode values (hybrid/context/tools
   not hybrid/honcho/local), and note that setup redirects to
   hermes memory setup.

2. build-a-hermes-plugin.md: Replace 'ctx.register_command() —
   planned but not yet implemented' with the actual implemented
   ctx.register_cli_command() API. Add full Register CLI commands
   section with code example.

3. memory-provider-plugin.md: Add 'Adding CLI Commands' section
   documenting the register_cli(subparser) convention for memory
   provider plugins, active-provider gating, and directory structure.

4. plugins.md: Add CLI command registration to the capabilities table.
2026-04-05 12:47:27 -07:00
4 changed files with 110 additions and 10 deletions

View File

@@ -192,6 +192,59 @@ mgr.on_session_end([])
mgr.shutdown_all() mgr.shutdown_all()
``` ```
## Adding CLI Commands
Memory provider plugins can register their own CLI subcommand tree (e.g. `hermes my-provider status`, `hermes my-provider config`). This uses a convention-based discovery system — no changes to core files needed.
### How it works
1. Add a `cli.py` file to your plugin directory
2. Define a `register_cli(subparser)` function that builds the argparse tree
3. The memory plugin system discovers it at startup via `discover_plugin_cli_commands()`
4. Your commands appear under `hermes <provider-name> <subcommand>`
**Active-provider gating:** Your CLI commands only appear when your provider is the active `memory.provider` in config. If a user hasn't configured your provider, your commands won't show in `hermes --help`.
### Example
```python
# plugins/memory/my-provider/cli.py
def my_command(args):
"""Handler dispatched by argparse."""
sub = getattr(args, "my_command", None)
if sub == "status":
print("Provider is active and connected.")
elif sub == "config":
print("Showing config...")
else:
print("Usage: hermes my-provider <status|config>")
def register_cli(subparser) -> None:
"""Build the hermes my-provider argparse tree.
Called by discover_plugin_cli_commands() at argparse setup time.
"""
subs = subparser.add_subparsers(dest="my_command")
subs.add_parser("status", help="Show provider status")
subs.add_parser("config", help="Show provider config")
subparser.set_defaults(func=my_command)
```
### Reference implementation
See `plugins/memory/honcho/cli.py` for a full example with 13 subcommands, cross-profile management (`--target-profile`), and config read/write.
### Directory structure with CLI
```
plugins/memory/my-provider/
├── __init__.py # MemoryProvider implementation + register()
├── plugin.yaml # Metadata
├── cli.py # register_cli(subparser) — CLI commands
└── README.md # Setup instructions
```
## Single Provider Rule ## Single Provider Rule
Only **one** external memory provider can be active at a time. If a user tries to register a second, the MemoryManager rejects it with a warning. This prevents tool schema bloat and conflicting backends. Only **one** external memory provider can be active at a time. If a user tries to register a second, the MemoryManager rejects it with a warning. This prevents tool schema bloat and conflicting backends.

View File

@@ -237,7 +237,7 @@ def register(ctx):
- Called exactly once at startup - Called exactly once at startup
- `ctx.register_tool()` puts your tool in the registry — the model sees it immediately - `ctx.register_tool()` puts your tool in the registry — the model sees it immediately
- `ctx.register_hook()` subscribes to lifecycle events - `ctx.register_hook()` subscribes to lifecycle events
- `ctx.register_command()` _planned but not yet implemented_ - `ctx.register_cli_command()` registers a CLI subcommand (e.g. `hermes my-plugin <subcommand>`)
- If this function crashes, the plugin is disabled but Hermes continues fine - If this function crashes, the plugin is disabled but Hermes continues fine
## Step 6: Test it ## Step 6: Test it
@@ -481,6 +481,44 @@ def register(ctx):
When multiple plugins return context from `pre_llm_call`, their outputs are joined with double newlines and appended to the user message together. The order follows plugin discovery order (alphabetical by plugin directory name). When multiple plugins return context from `pre_llm_call`, their outputs are joined with double newlines and appended to the user message together. The order follows plugin discovery order (alphabetical by plugin directory name).
### Register CLI commands
Plugins can add their own `hermes <plugin>` subcommand tree:
```python
def _my_command(args):
"""Handler for hermes my-plugin <subcommand>."""
sub = getattr(args, "my_command", None)
if sub == "status":
print("All good!")
elif sub == "config":
print("Current config: ...")
else:
print("Usage: hermes my-plugin <status|config>")
def _setup_argparse(subparser):
"""Build the argparse tree for hermes my-plugin."""
subs = subparser.add_subparsers(dest="my_command")
subs.add_parser("status", help="Show plugin status")
subs.add_parser("config", help="Show plugin config")
subparser.set_defaults(func=_my_command)
def register(ctx):
ctx.register_tool(...)
ctx.register_cli_command(
name="my-plugin",
help="Manage my plugin",
setup_fn=_setup_argparse,
handler_fn=_my_command,
)
```
After registration, users can run `hermes my-plugin status`, `hermes my-plugin config`, etc.
**Memory provider plugins** use a convention-based approach instead: add a `register_cli(subparser)` function to your plugin's `cli.py` file. The memory plugin discovery system finds it automatically — no `ctx.register_cli_command()` call needed. See the [Memory Provider Plugin guide](/docs/developer-guide/memory-provider-plugin#adding-cli-commands) for details.
**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.
### Distribute via pip ### Distribute via pip
For sharing plugins publicly, add an entry point to your Python package: For sharing plugins publicly, add an entry point to your Python package:

View File

@@ -363,22 +363,30 @@ Notes:
## `hermes honcho` ## `hermes honcho`
```bash ```bash
hermes honcho <subcommand> hermes honcho [--target-profile NAME] <subcommand>
``` ```
Manage Honcho cross-session memory integration. This command is provided by the Honcho memory provider plugin and is only available when `memory.provider` is set to `honcho` in your config.
The `--target-profile` flag lets you manage another profile's Honcho config without switching to it.
Subcommands: Subcommands:
| Subcommand | Description | | Subcommand | Description |
|------------|-------------| |------------|-------------|
| `setup` | Interactive Honcho setup wizard. | | `setup` | Redirects to `hermes memory setup` (unified setup path). |
| `status` | Show current Honcho config and connection status. | | `status [--all]` | Show current Honcho config and connection status. `--all` shows a cross-profile overview. |
| `peers` | Show peer identities across all profiles. |
| `sessions` | List known Honcho session mappings. | | `sessions` | List known Honcho session mappings. |
| `map` | Map the current directory to a Honcho session name. | | `map [name]` | Map the current directory to a Honcho session name. Omit `name` to list current mappings. |
| `peer` | Show or update peer names and dialectic reasoning level. | | `peer` | Show or update peer names and dialectic reasoning level. Options: `--user NAME`, `--ai NAME`, `--reasoning LEVEL`. |
| `mode` | Show or set memory mode: `hybrid`, `honcho`, or `local`. | | `mode [mode]` | Show or set recall mode: `hybrid`, `context`, or `tools`. Omit to show current. |
| `tokens` | Show or set token budgets for context and dialectic. | | `tokens` | Show or set token budgets for context and dialectic. Options: `--context N`, `--dialectic N`. |
| `identity` | Seed or show the AI peer identity representation. | | `identity [file] [--show]` | Seed or show the AI peer identity representation. |
| `migrate` | Migration guide from openclaw-honcho to Hermes Honcho. | | `enable` | Enable Honcho for the active profile. |
| `disable` | Disable Honcho for the active profile. |
| `sync` | Sync Honcho config to all existing profiles (creates missing host blocks). |
| `migrate` | Step-by-step migration guide from openclaw-honcho to Hermes Honcho. |
## `hermes memory` ## `hermes memory`

View File

@@ -83,6 +83,7 @@ Project-local plugins under `./.hermes/plugins/` are disabled by default. Enable
|-----------|-----| |-----------|-----|
| Add tools | `ctx.register_tool(name, schema, handler)` | | Add tools | `ctx.register_tool(name, schema, handler)` |
| Add hooks | `ctx.register_hook("post_tool_call", callback)` | | Add hooks | `ctx.register_hook("post_tool_call", callback)` |
| Add CLI commands | `ctx.register_cli_command(name, help, setup_fn, handler_fn)` — adds `hermes <plugin> <subcommand>` |
| Inject messages | `ctx.inject_message(content, role="user")` — see [Injecting Messages](#injecting-messages) | | Inject messages | `ctx.inject_message(content, role="user")` — see [Injecting Messages](#injecting-messages) |
| Ship data files | `Path(__file__).parent / "data" / "file.yaml"` | | Ship data files | `Path(__file__).parent / "data" / "file.yaml"` |
| Bundle skills | Copy `skill.md` to `~/.hermes/skills/` at load time | | Bundle skills | Copy `skill.md` to `~/.hermes/skills/` at load time |