Hermes: the plugins and their hooks
1. What? — Definition and context
Section titled “1. What? — Definition and context”Skills are text: they steer the model. Plugins are Python code: they run, whatever the model decides.
A plugin registers on hooks of the Hermes lifecycle and can, depending on the hook, observe an event, rewrite a message before processing, or expose new tools to the agent.
The four active plugins
Section titled “The four active plugins”| Plugin | Version | Contribution | Author |
|---|---|---|---|
telegram-voice-transcriptor | 1.1.0 | pre_gateway_dispatch hook | Custom |
telegram-message-editor | 1.0.0 | telegram_status_message tool | Custom |
codex-usage-alert | 1.0.0 | post_api_request hook | Custom |
mnemosyne | 0.4.0 | 20 tools + 3 hooks | Third party (Abdias J) |
The hooks used
Section titled “The hooks used”| Hook | Moment | Can do |
|---|---|---|
pre_gateway_dispatch | Message received, before processing | Rewrite or redirect the event |
pre_llm_call | Before the model call | Inject context into the prompt |
on_session_start | Session opening | Load an initial state |
post_tool_call | After a tool call | Observe, capture |
post_api_request | After a successful LLM call | Observe, trigger a side effect |
2. Why? — Stakes and motivations
Section titled “2. Why? — Stakes and motivations”Why user plugins rather than patching the core?
Section titled “Why user plugins rather than patching the core?”The application tree /opt/hermes belongs to the image. A change there survives until the next update — and then disappears without a sound, which is the worst possible ending for a customisation.
User plugins live in /opt/data/plugins/, that is, in the bind mount. They survive docker compose up --force-recreate as well as image updates, and go into the daily backup.
It is the same rule as Mnemosyne’s wrapper mode: everything meant to last lives in the volume, never in the image.
Plugin or MCP tool?
Section titled “Plugin or MCP tool?”Both add capabilities, but not in the same place nor at the same price.
| N8N MCP tool | Plugin | |
|---|---|---|
| Where | A node in a workflow | Python inside the container |
| Access | Whatever N8N can reach | The Hermes runtime itself |
| Change | Edit the workflow, restart the container | Edit the file, restart the container |
| Can react to an event | No — only be called | Yes, through hooks |
The dividing line is simple: a business action becomes an MCP tool; a behaviour that must fire without the agent deciding becomes a plugin.
3. How? — Technical implementation
Section titled “3. How? — Technical implementation”telegram-voice-transcriptor
Section titled “telegram-voice-transcriptor”On a Telegram voice message, the plugin rewrites the event to inject the block of the transcriptor-fr-voice skill. The STT pipeline then prefixes the transcript as a quote, and the agent replies with the cleaned-up French text.
Its interest lies less in what it does than in what it refuses to fire on.
The hook is also fail-open: any exception is logged as a warning and the message goes on to normal processing. A broken skill or a failed import must never swallow a voice message.
telegram-message-editor
Section titled “telegram-message-editor”This plugin exposes one tool, telegram_status_message, with two actions: create sends a message and returns its message_id, update edits that same message in place. 4096-character cap, and by default the current conversation when the call comes from Telegram.
The problem it solves is an ergonomics problem. An agent working for several minutes on a multi-step task has a choice between staying silent — and looking stuck — or sending one message per step, and drowning the conversation. In-place editing gives a third option: a single dashboard that updates itself.
codex-usage-alert
Section titled “codex-usage-alert”Hermes shares the ChatGPT subscription with CLI Ollama and the N8N workflows. Hitting the weekly cap produces no signal until the bot starts answering with errors.
The plugin registers on post_api_request, reacts only to openai-codex provider calls, and alerts when account consumption crosses a threshold (90% by default).
Its four guardrails are worth noting, because they are what separates an acceptable observation plugin from one that degrades the service:
| Guardrail | Implementation |
|---|---|
| Non-blocking | The hook starts at most one short daemon thread and hands control back immediately |
| Controlled load | A 300 s cooldown avoids calling the backend again on every message of an active conversation |
| Anti-spam | One alert per threshold + quota window + reset time combination, with history bounded to 200 keys |
| Fail-open | Any error is logged and never affects the Hermes response |
The common principle: a plugin grafted onto a hot path must never be what breaks or slows the response.
mnemosyne
Section titled “mnemosyne”The only third-party plugin of the set, and by far the largest: 20 tools and 3 hooks (pre_llm_call, on_session_start, post_tool_call). It is installed in wrapper mode and has a dedicated article.
Its presence in this list says something about the extension system: long-term memory, arguably the agent’s most structuring feature, installs through the same mechanism as a quota alert.
Deployment
Section titled “Deployment”A plugin is a directory with a plugin.yaml and an __init__.py exposing register(ctx).
def register(ctx) -> None: ctx.register_hook("post_api_request", _on_post_api_request)name: codex-usage-alertversion: 1.0.0description: "Non-blocking Telegram Home alert when OpenAI Codex account usage crosses a threshold."author: Guillaume PARRAT + Hermes Agentprovides_hooks: - post_api_requestOnly telegram-voice-transcriptor has versioned source in the repository; deployment happens by copy then restart:
cp -r ai-stack/hermes/plugins/telegram-voice-transcriptor ai-stack/hermes/data/plugins/docker compose -f ai-stack/docker-compose.yaml restart hermesdocker exec hermes hermes plugins list # expected status: enabled4. What if? — Outlook and limits
Section titled “4. What if? — Outlook and limits”Current limits
Section titled “Current limits”| Limit | Impact | Mitigation |
|---|---|---|
| Three plugins out of four unversioned | Only the transcriptor has source in the repository; the others exist only in production | Daily backup; porting to the repository still to do |
| Restart required | Any change forces a container restart | Batch the changes |
| No automated test | A broken plugin is discovered in use | Fail-open limits the damage to one lost feature |
| Hooks unversioned upstream | An upstream signature change breaks a plugin | hermes plugins list after every image update |
| No isolation | A plugin runs inside the gateway process | Discipline: non-blocking and fail-open by default |
Evolution scenarios
Section titled “Evolution scenarios”If plugins must be versioned:
ai-stack/hermes/plugins/already exists and holds the transcriptor — the other three follow the same pattern.- Main benefit: being able to roll back after an upstream update that breaks a hook.
If a plugin must become blocking:
- The typical case would be a real approval chain before sensitive actions, rather than the current system prompt rule.
- A
pre_tool_callhook would fit — but a blocking plugin on the hot path needs an explicit timeout and fallback behaviour, otherwise a plugin failure freezes the agent.
If observability must improve:
post_api_requestandpost_tool_callare the natural points to export metrics.- A plugin pushing a counter to Prometheus would give Hermes the same visibility as the rest of the stacks in Grafana.
Related pages
Section titled “Related pages”Hermes
Section titled “Hermes”- Hermes Agent — The deployment and plugin activation
- Mnemosyne memory — The largest plugin of the set
- Skills —
hermes-user-pluginsandhermes-runtime-plugins, the writing toolkit - MCP tools — The other way to add a capability
Workflows
Section titled “Workflows”- Codex CLI Integration — In-place editing, N8N version
- Voice Transcription — The other transcription path
Infrastructure
Section titled “Infrastructure”- Database backup — Deployed plugins are backed up