Reference docs fixes: - cli-commands.md: remove non-existent --provider alibaba, add hermes profile/completion/plugins/mcp to top-level table, add --profile/-p global flag, add --source chat option - slash-commands.md: add /yolo and /commands, fix /q alias conflict (resolves to /queue not /quit), add missing aliases (/bg, /set-home, /reload_mcp, /gateway) - toolsets-reference.md: fix hermes-api-server (not same as hermes-cli, omits clarify/send_message/text_to_speech) - profile-commands.md: fix show name required not optional, --clone-from not --from, add --remove/--name to alias, fix alias path, fix export/ import arg types, remove non-existent fish completion - tools-reference.md: add EXA_API_KEY to web tools requires_env - mcp-config-reference.md: add auth key for OAuth, tool name sanitization - environment-variables.md: add EXA_API_KEY, update provider values - plugins.md: remove non-existent ctx.register_command(), add ctx.inject_message() Feature docs additions: - security.md: add /yolo mode, approval modes (manual/smart/off), configurable timeout, expanded dangerous patterns table - cron.md: add wrap_response config, [SILENT] suppression - mcp.md: add dynamic tool discovery, MCP sampling support - cli.md: add Ctrl+Z suspend, busy_input_mode, tool_preview_length - docker.md: add skills/credential file mounting Messaging platform docs: - telegram.md: add webhook mode, DoH fallback IPs - slack.md: add multi-workspace OAuth support - discord.md: add DISCORD_IGNORE_NO_MENTION - matrix.md: add MSC3245 native voice messages - feishu.md: expand from 129 to 365 lines (encrypt key, verification token, group policy, card actions, media, rate limiting, markdown, troubleshooting) - wecom.md: expand from 86 to 264 lines (per-group allowlists, media, AES decryption, stream replies, reconnection, troubleshooting) Configuration docs: - quickstart.md: add DeepSeek, Copilot, Copilot ACP providers - configuration.md: add DeepSeek provider, Exa web backend, terminal env_passthrough/images, browser.command_timeout, compression params, discord config, security/tirith config, timezone, auxiliary models 21 files changed, ~1000 lines added
108 lines
4.5 KiB
Markdown
108 lines
4.5 KiB
Markdown
---
|
|
sidebar_position: 20
|
|
---
|
|
|
|
# Plugins
|
|
|
|
Hermes has a plugin system for adding custom tools, hooks, and integrations without modifying core code.
|
|
|
|
**→ [Build a Hermes Plugin](/docs/guides/build-a-hermes-plugin)** — step-by-step guide with a complete working example.
|
|
|
|
## Quick overview
|
|
|
|
Drop a directory into `~/.hermes/plugins/` with a `plugin.yaml` and Python code:
|
|
|
|
```
|
|
~/.hermes/plugins/my-plugin/
|
|
├── plugin.yaml # manifest
|
|
├── __init__.py # register() — wires schemas to handlers
|
|
├── schemas.py # tool schemas (what the LLM sees)
|
|
└── tools.py # tool handlers (what runs when called)
|
|
```
|
|
|
|
Start Hermes — your tools appear alongside built-in tools. The model can call them immediately.
|
|
|
|
Project-local plugins under `./.hermes/plugins/` are disabled by default. Enable them only for trusted repositories by setting `HERMES_ENABLE_PROJECT_PLUGINS=true` before starting Hermes.
|
|
|
|
## What plugins can do
|
|
|
|
| Capability | How |
|
|
|-----------|-----|
|
|
| Add tools | `ctx.register_tool(name, schema, handler)` |
|
|
| Add hooks | `ctx.register_hook("post_tool_call", callback)` |
|
|
| Inject messages | `ctx.inject_message(content, role="user")` — see [Injecting Messages](#injecting-messages) |
|
|
| Ship data files | `Path(__file__).parent / "data" / "file.yaml"` |
|
|
| Bundle skills | Copy `skill.md` to `~/.hermes/skills/` at load time |
|
|
| Gate on env vars | `requires_env: [API_KEY]` in plugin.yaml |
|
|
| Distribute via pip | `[project.entry-points."hermes_agent.plugins"]` |
|
|
|
|
## Plugin discovery
|
|
|
|
| Source | Path | Use case |
|
|
|--------|------|----------|
|
|
| User | `~/.hermes/plugins/` | Personal plugins |
|
|
| Project | `.hermes/plugins/` | Project-specific plugins (requires `HERMES_ENABLE_PROJECT_PLUGINS=true`) |
|
|
| pip | `hermes_agent.plugins` entry_points | Distributed packages |
|
|
|
|
## Available hooks
|
|
|
|
Plugins can register callbacks for these lifecycle events. See the **[Event Hooks page](/docs/user-guide/features/hooks#plugin-hooks)** for full details, callback signatures, and examples.
|
|
|
|
| Hook | Fires when |
|
|
|------|-----------|
|
|
| `pre_tool_call` | Before any tool executes |
|
|
| `post_tool_call` | After any tool returns |
|
|
| `pre_llm_call` | Once per turn, before the LLM loop — can return `{"context": "..."}` to inject into the system prompt |
|
|
| `post_llm_call` | Once per turn, after the LLM loop completes |
|
|
| `on_session_start` | New session created (first turn only) |
|
|
| `on_session_end` | End of every `run_conversation` call |
|
|
|
|
## Managing plugins
|
|
|
|
```bash
|
|
hermes plugins # interactive toggle UI — enable/disable with checkboxes
|
|
hermes plugins list # table view with enabled/disabled status
|
|
hermes plugins install user/repo # install from Git
|
|
hermes plugins update my-plugin # pull latest
|
|
hermes plugins remove my-plugin # uninstall
|
|
hermes plugins enable my-plugin # re-enable a disabled plugin
|
|
hermes plugins disable my-plugin # disable without removing
|
|
```
|
|
|
|
Running `hermes plugins` with no arguments launches an interactive curses checklist (same UI as `hermes tools`) where you can toggle plugins on/off with arrow keys and space.
|
|
|
|
Disabled plugins remain installed but are skipped during loading. The disabled list is stored in `config.yaml` under `plugins.disabled`:
|
|
|
|
```yaml
|
|
plugins:
|
|
disabled:
|
|
- my-noisy-plugin
|
|
```
|
|
|
|
In a running session, `/plugins` shows which plugins are currently loaded.
|
|
|
|
## Injecting Messages
|
|
|
|
Plugins can inject messages into the active conversation using `ctx.inject_message()`:
|
|
|
|
```python
|
|
ctx.inject_message("New data arrived from the webhook", role="user")
|
|
```
|
|
|
|
**Signature:** `ctx.inject_message(content: str, role: str = "user") -> bool`
|
|
|
|
How it works:
|
|
|
|
- If the agent is **idle** (waiting for user input), the message is queued as the next input and starts a new turn.
|
|
- If the agent is **mid-turn** (actively running), the message interrupts the current operation — the same as a user typing a new message and pressing Enter.
|
|
- For non-`"user"` roles, the content is prefixed with `[role]` (e.g. `[system] ...`).
|
|
- Returns `True` if the message was queued successfully, `False` if no CLI reference is available (e.g. in gateway mode).
|
|
|
|
This enables plugins like remote control viewers, messaging bridges, or webhook receivers to feed messages into the conversation from external sources.
|
|
|
|
:::note
|
|
`inject_message` is only available in CLI mode. In gateway mode, there is no CLI reference and the method returns `False`.
|
|
:::
|
|
|
|
See the **[full guide](/docs/guides/build-a-hermes-plugin)** for handler contracts, schema format, hook behavior, error handling, and common mistakes.
|