Hermes Agent Plugin Development and Production Practices
This chapter is for advanced users: how to extend Hermes through the plugin system, how to migrate from OpenClaw, and best practices for security and cost when deploying Hermes to production.
Getting Started with Plugin Development
Hermes supports three types of plugins: general-purpose plugins (tools + hooks), memory providers, and context engines.
Example
hermes plugins
# Command-line management
hermes plugins list
hermes plugins install <path>
hermes plugins enable <name>
hermes plugins disable <name>
You can manage plugins in the dashboard. Use the following command to start the Dashboard:
hermes dashboard
Open the dashboard in your browser, open the plugin list on the left, and you can see the installed plugins:

Hook system
The most commonly used plugin capability is the Hook — injecting custom logic at key points in the Agent lifecycle:
Example
# Simple plugin example: record all LLM calls
from hermes.plugins import Plugin, hook
class LoggingPlugin(Plugin):
name = "logging-plugin"
@hook("pre_llm_call")
async def before_call(self, ctx):
# Trigger before each LLM call
print(f"[LOG] About to call LLM, current context length: {len(ctx.messages)}")
@hook("post_llm_call")
async def after_call(self, ctx, response):
# Trigger after each LLM call
print(f"[LOG] LLM call completed, response length: {len(response.content)}")
Available Hook Points
| Hook | Trigger timing | Typical use |
|---|---|---|
| pre_llm_call | Before LLM Calls | Record context, modify prompts |
| post_llm_call | After LLM Calls | Record responses, statistical analysis |
| pre_tool_call | Before tool invocation (can intercept/modify) | Permission verification, parameter filtering |
| post_tool_call | After the tool call | Result Auditing, Logging |
| on_message_received | When Receiving User Messages | Message preprocessing, sensitive word filtering |
| on_session_start | At the start of the session | Initialize resources, inject context |
| on_session_end | At the end of the session | Clean up resources, generate summary |
Registering Custom Tools
Add brand-new tool capabilities to the Agent through plugins:
Example
# Register custom tools — the Agent can use them just like built-in tools
from hermes.plugins import Plugin
class MyPlugin(Plugin):
name = "my-tools"
def register_tools(self, ctx):
# Register custom tools, visible in the agent's system prompt
ctx.register_tool(
name="my_custom_tool",
description="This tool does something, use when the user needs X",
parameters={
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "Input Parameter Description"
}
},
"required": ["input"]
},
handler=self.my_tool_handler
)
async def my_tool_handler(self, **kwargs):
# Actual Execution Logic of the Tool
input_text = kwargs.get("input", "")
# ... processing logic ...
return {"result": "done"}
Migrating from OpenClaw
If you are using OpenClaw, the official zero-downtime migration solution is provided:
Example
openclaw export --format hermes > openclaw-config.json
# Import to Hermes
hermes import --from openclaw openclaw-config.json
# Verify Migration Results
hermes doctor
Main Concept Comparison
| Concepts | OpenClaw | Hermes |
|---|---|---|
| Agent Definition | JSON Agent configuration | SOUL.md + config.yaml |
| Workflow | Manually write YAML flows | Skill (SKILL.md) |
| Memory Backend | External database | Built-in SQLite + Pluggable |
| Skills/Tools | Code Plugin | Markdown skill files |
| multiple instances | Multi-process configuration | Profile system |
Production environment best practices
Security Checklist
Recommended Security Configuration for Production Deployment:
Example
# Recommended Security Configuration for Production Environment
terminal:
backend: docker # Required: isolate Agent command execution environment
approvals:
mode: smart # Dangerous commands require approval (or manual is stricter).
cron_mode: deny # Scheduled tasks reject dangerous commands by default
security:
redact_secrets: true # Automatically redact sensitive information in logs (enabled by default)
Access control in environment variables:
Example
# Access Control Configuration for Production Environment
GATEWAY_ALLOW_ALL_USERS=false # Never allow all users
TELEGRAM_ALLOWED_USERS=your user ID# Explicit whitelist
Token cost control
Auxiliary tasks use cheaper models, significantly reducing operating costs:
Example
# Use a separate model for auxiliary tasks to reduce Token costs
auxiliary:
background_review:
provider: openrouter
model: google/gemini-3-flash-preview # No Need to Use the Main Model
vision:
provider: openrouter
model: google/gemini-2.5-flash-preview
session_search:
provider: openrouter
model: google/gemini-3-flash-preview
Multi-Profile gateway monitoring
Example
hermes profile list
# Batch restart all gateways
for profile in coder assistant researcher; do
$profile gateway restart
done
Update Strategy
Update code and built-in skills of all Profiles with one command:
Example
hermes update
# → Code update (12 commits)
# → Skill sync:
# default (already latest)
# coder (+2 new skills)
# assistant (+2 new skills)
other extensionsUser-modified skills will never be overwritten. Updates only sync the new and changed parts of built-in skills.