feat(plugins): add pre_gateway_dispatch hook - #15050
Merged
Merged
Conversation
Introduces a new plugin hook `pre_gateway_dispatch` fired once per
incoming MessageEvent in `_handle_message`, after the internal-event
guard but before the auth / pairing chain. Plugins may return a dict
to influence flow:
{"action": "skip", "reason": "..."} -> drop (no reply)
{"action": "rewrite", "text": "..."} -> replace event.text
{"action": "allow"} / None -> normal dispatch
Motivation: gateway-level message-flow patterns that don't fit cleanly
into any single adapter — e.g. listen-only group-chat windows (buffer
ambient messages, collapse on @mention), or human-handover silent
ingest (record messages while an owner handles the chat manually).
Today these require forking core; with this hook they can live in a
single profile-agnostic plugin.
Hook runs BEFORE auth so plugins can handle unauthorized senders
(e.g. customer-service handover ingest) without triggering the
pairing-code flow. Exceptions in plugin callbacks are caught and
logged; the first non-None action dict wins, remaining results are
ignored.
Includes:
- `VALID_HOOKS` entry + inline doc in `hermes_cli/plugins.py`
- Invocation block in `gateway/run.py::_handle_message`
- 5 new tests in `tests/gateway/test_pre_gateway_dispatch.py`
(skip, rewrite, allow, exception safety, internal-event bypass)
- 2 additional tests in `tests/hermes_cli/test_plugins.py`
- Table entry in `website/docs/user-guide/features/plugins.md`
Made-with: Cursor
… section
Follow-up to aeff6dfe:
- Fix semantic error in VALID_HOOKS inline comment ("after core auth" ->
"before auth"). Hook intentionally runs BEFORE auth so plugins can
handle unauthorized senders without triggering the pairing flow.
- Fix wrong class name in the same comment (HermesGateway ->
GatewayRunner, matching gateway/run.py).
- Add a full ### pre_gateway_dispatch section in
website/docs/user-guide/features/hooks.md (matches the pattern of
every other plugin hook: signature, params table, fires-where,
return-value table, use cases, two worked examples) plus a row in
the quick-reference table.
- Add the anchor link on the plugins.md table row so it matches the
other hook entries.
No code behavior change.
13 tasks
github-actions Bot
pushed a commit
to pebble-tech/hermes-agent
that referenced
this pull request
Apr 27, 2026
This is the sole commit on ops-overlay. It carries:
- .github/workflows/sync-upstream.yml: daily rebase + rebuild of main
on top of upstream/main + ops-overlay + each feature branch.
- FORK.md: branch layout, sync model, recovery procedure.
Steady state (2026-04-26 onward): both feature branches we used to
carry have merged upstream (PRs NousResearch#13445 and NousResearch#14904 via NousResearch#15050 and
NousResearch#15191). FEATURE_BRANCHES is now empty; main collapses to
upstream/main + ops-overlay. The fork stays alive so customer VPSes
have a stable deploy target rebuilt on our schedule.
github-actions Bot
pushed a commit
to pebble-tech/hermes-agent
that referenced
this pull request
Apr 30, 2026
This is the sole commit on ops-overlay. It carries:
- .github/workflows/sync-upstream.yml: daily rebase + rebuild of main
on top of upstream/main + ops-overlay + each feature branch.
- FORK.md: branch layout, sync model, recovery procedure.
Steady state (2026-04-26 onward): both feature branches we used to
carry have merged upstream (PRs NousResearch#13445 and NousResearch#14904 via NousResearch#15050 and
NousResearch#15191). FEATURE_BRANCHES is now empty; main collapses to
upstream/main + ops-overlay. The fork stays alive so customer VPSes
have a stable deploy target rebuilt on our schedule.
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Salvage of #13445 onto current main.
Adds
pre_gateway_dispatchplugin hook fired inGatewayRunner._handle_messageafter the internal-event guard, before auth/pairing. Plugins return a dict to influence flow:{"action": "skip", "reason": ...}— drop (no reply, plugin handled){"action": "rewrite", "text": ...}— replace event.text, continue normally{"action": "allow"}/None— normal dispatchConsumer plugin exists out-of-tree: https://github.com/pebble-tech/hermes-plugin-gateway-policy (listen-only windows, human handover).
Changes
hermes_cli/plugins.py— addpre_gateway_dispatchtoVALID_HOOKS+ inline docgateway/run.py— invoke hook in_handle_message(before auth, skips internal events), dispatch skip/rewrite/allow actionstests/gateway/test_pre_gateway_dispatch.py— 5 tests (skip, rewrite, allow, exception safety, internal-event bypass)tests/hermes_cli/test_plugins.py— 2 tests (registration, action-dict collection)website/docs/user-guide/features/{hooks,plugins}.md— docsscripts/release.py— AUTHOR_MAP entry for @keiravoss94Validation
scripts/run_tests.sh tests/gateway/test_pre_gateway_dispatch.py tests/hermes_cli/test_plugins.py: 63/63 passed. E2E verified hook is in VALID_HOOKS +dataclasses.replace(event, text=...)preserves source fields.Original PR #13445 by @keiravoss94, commits cherry-picked with authorship preserved.