# Hermes Agent event hooks explained

> Choose between gateway hooks, shell hooks, plugin hooks and outbound webhooks, and set up a hook that logs, blocks or notifies without surprising you later.

Canonical: https://hermeswatcher.com/learn/event-hooks-explained  
Section: Learn · Automation & scheduling  
Last reviewed: Oct 20, 2026  
Basis: Explained from the official Hermes Agent docs and repository (Nous Research). Steps follow the linked official sources.

## Four hook systems, four jobs

Hooks let you run code at fixed points in Hermes' lifecycle: when a session starts, before a tool runs, after the model replies, when a subagent finishes. Hermes has four separate systems for this, and choosing the right one is most of the work:

- Gateway hooks: a `HOOK.yaml` and a `handler.py` in a folder under `~/.hermes/hooks/`. They run only in the messaging gateway and suit logging, alerts and webhooks.
- Shell hooks: a `hooks:` block in `config.yaml` that points at any executable script. They run in the CLI, the gateway, and the Desktop, TUI and dashboard chats, and they can block tool calls or inject context.
- Plugin hooks: Python callbacks registered with `ctx.register_hook()` inside a plugin. They run in the CLI and the gateway.
- Outbound webhooks: a `hooks.outbound:` list that POSTs signed JSON to HTTP endpoints when events fire. Nothing runs on your machine.

## Gateway hooks for chat-side alerts

A gateway hook is a folder with two files. `HOOK.yaml` lists the events it listens to, such as `gateway:startup`, `session:start`, `session:reset`, `agent:start`, `agent:step`, `agent:end` or the wildcard `command:*`. `handler.py` defines a function named `handle` that receives the event type and a context dictionary. It can be async or a regular function. Errors are caught and logged, so a broken hook never crashes the agent.

Be aware of the trust model. Putting the files in the folder is the opt-in. There is no enable list and no sandbox, and the handler runs inside the gateway process with the same access the gateway has. Read any hook's `handler.py` before you install it, just as you would a plugin. Gateway hooks load once, when the gateway starts, so restart the gateway after adding one.

## Shell hooks for guardrails and context

Shell hooks are where most people should start, because they need no Python and work almost everywhere. Each entry names a plugin-hook event, an optional `matcher` regex (used only for `pre_tool_call` and `post_tool_call`), a `command`, and an optional `timeout` (default 60 seconds, capped at 300). Hermes sends a JSON payload to the script on stdin and reads JSON back from stdout.

Three uses come up most often. A `post_tool_call` hook matching `write_file|patch` can auto-format files the agent just wrote. A `pre_tool_call` hook matching `terminal` can block a command by printing `{"decision": "block", "reason": "..."}`, or simply by exiting with code 2. A `pre_llm_call` hook can return `{"context": "..."}` to add something like `git status` output to the next turn.

## Consent and fail-closed behaviour

The first time Hermes sees a given event and command pair, it asks before running it, and stores your answer in `~/.hermes/shell-hooks-allowlist.json`. Only a foreground `hermes chat` ever shows that prompt. The gateway, cron and other headless runs skip any hook that hasn't been approved and log a warning, so approve new hooks interactively first, or use `--accept-hooks`, `HERMES_ACCEPT_HOOKS=1` or `hooks_auto_accept: true` if you understand the trade-off.

Two details matter for safety. First, consent is tied to the command string, not the script's contents, so later edits to the script are trusted silently. `hermes hooks doctor` flags scripts that changed after approval. Second, shell hooks fail open by default: a crash or timeout logs a warning and the tool call goes ahead. For a security check such as a secret scanner, set `fail_closed: true` on the `pre_tool_call` entry so a broken check blocks the call instead.

## Testing and maintaining hooks

- `hermes hooks list` shows configured shell hooks and outbound targets, with matcher, timeout and consent status.
- `hermes hooks test <event>` fires matching hooks with a synthetic payload and prints the parsed response. Use `--for-tool terminal` to test a tool matcher.
- `hermes hooks revoke <command>` removes a consent entry. A running gateway stops running that hook within about 30 seconds.
- `hermes hooks doctor` checks the executable bit, consent, changed scripts, JSON output and rough run time.
- The dashboard's System page can also list, create and remove shell hooks, and its create form includes an explicit consent checkbox.

## Outbound webhooks to tell other systems

If all you need is for another system to find out that something happened, such as a CI server or a monitoring board, use `hooks.outbound:` instead of writing a script. Each entry has a `url`, a list of `events` (for example `on_session_end` or `subagent_stop`), an optional `matcher` for tool events, and ideally `secret_env`, which names an environment variable holding the signing secret. Entries without a secret are sent unsigned and shown as `UNSIGNED` by `hermes hooks list`. Payloads include tool inputs, so only send them to endpoints you trust, preferably over `https://`.

## Related guides

- [Hermes Agent security: approvals, allowlists, sandboxing](https://hermeswatcher.com/learn/security-model-approvals-and-sandboxing.md)
- [Hermes Agent skills vs plugins vs MCP: which to use](https://hermeswatcher.com/learn/skills-plugins-and-mcp.md)
- [Hermes Agent messaging gateway explained](https://hermeswatcher.com/learn/messaging-gateway-explained.md)
- [Hermes Agent web dashboard: a quick tour](https://hermeswatcher.com/learn/web-dashboard-tour.md)

## Related tools

- [Know whether an automation actually worked](https://hermeswatcher.com/workflows/reliable-recurring-automation.md)
- [Plugins: add tools and lifecycle behavior](https://hermeswatcher.com/tools/plugins.md)
- [Command approvals: decide what the agent may run unattended](https://hermeswatcher.com/tools/approvals-security.md)
- [CLI: run bounded tasks and inspect the working environment](https://hermeswatcher.com/tools/cli.md)
- [Telegram: reach Hermes from a private bot conversation](https://hermeswatcher.com/tools/telegram.md)

## Sources

- [Event Hooks (official docs)](https://hermes-agent.nousresearch.com/docs/user-guide/features/hooks)
- [CLI Commands Reference: hermes hooks (official docs)](https://hermes-agent.nousresearch.com/docs/reference/cli-commands)
- [Security (official docs)](https://hermes-agent.nousresearch.com/docs/user-guide/security)

---

HermesWatcher is an independent guide. It is not affiliated with or endorsed by Nous Research. The [official Hermes Agent documentation](https://hermes-agent.nousresearch.com/docs) and [repository](https://github.com/NousResearch/hermes-agent) from Nous Research are the authority; each page here lists the official sources it was written from. If this site and the official docs disagree, trust the official docs. Index for agents: https://hermeswatcher.com/llms.txt
