hermes - 💡(How to fix) Fix [Feature]: feat(gateway): Support multiple delivery targets per webhook route

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Fix Action

Fix / Workaround

  • Backward compatible: existing deliver: "string" + deliver_extra format must continue working unchanged
    • Concurrent dispatch: all targets delivered in parallel via asyncio.gather
    • Best-effort semantics: one target failing does not block others; success if ≥1 target succeeds
    • Template rendering: target extras support {dot.notation} payload templates (same as deliver_extra today)
    • Startup validation: deliver_only routes with list format must validate every target has a real type (not log)
    • CLI support: hermes webhook subscribe should accept --deliver multiple times

Scope

  ┌──────────────────────────────┬───────────────────────────────────────────────────────┐
  │          Component           │                        Change                         │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ gateway/platforms/webhook.py │ Core multi-target dispatch logic                      │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ hermes_cli/webhook.py        │ CLI --deliver multi-target parsing                    │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ hermes_cli/main.py           │ Argparse --deliver → action="append"                  │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ Tests                        │ New test file for multi-deliver scenarios             │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ Docs                         │ Update webhooks.md with Multi-Target Delivery section │
  └──────────────────────────────┴───────────────────────────────────────────────────────┘

Use Cases

Code Example

routes:
    pr-review:
      events: ["pull_request"]
      secret: "webhook-secret"
      prompt: "Review PR #{number}: {pull_request.title}"
      deliver:
        - type: "github_comment"
          repo: "{repository.full_name}"
          pr_number: "{number}"
        - type: "telegram"
          chat_id: "{notify.telegram_chat_id}"
        - type: "discord"
          chat_id: "987654321"

---

┌──────────────────────────────┬───────────────────────────────────────────────────────┐
ComponentChange  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ gateway/platforms/webhook.pyCore multi-target dispatch logic                      │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ hermes_cli/webhook.pyCLI --deliver multi-target parsing                    │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ hermes_cli/main.pyArgparse --deliver → action="append"  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
TestsNew test file for multi-deliver scenarios             │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
DocsUpdate webhooks.md with Multi-Target Delivery section │
  └──────────────────────────────┴───────────────────────────────────────────────────────┘

---
RAW_BUFFERClick to expand / collapse

Problem or Use Case

Currently, each webhook route can only deliver responses to a single platform. The deliver field accepts only a string value (e.g. "telegram"), and deliver_extra provides config for that one target.

Users who need to fan out a single webhook event to multiple platforms (e.g., post a PR review comment on GitHub AND notify the team on Telegram AND log to Discord) must create duplicate routes — each triggering an independent agent run. This wastes LLM tokens and adds latency for what should be a single "process once, deliver everywhere" operation.

Proposed Solution

Allow the deliver field to accept a list of target objects in addition to the existing string format:

routes:
  pr-review:
    events: ["pull_request"]
    secret: "webhook-secret"
    prompt: "Review PR #{number}: {pull_request.title}"
    deliver:
      - type: "github_comment"
        repo: "{repository.full_name}"
        pr_number: "{number}"
      - type: "telegram"
        chat_id: "{notify.telegram_chat_id}"
      - type: "discord"
        chat_id: "987654321"

Requirements

  • Backward compatible: existing deliver: "string" + deliver_extra format must continue working unchanged
  • Concurrent dispatch: all targets delivered in parallel via asyncio.gather
  • Best-effort semantics: one target failing does not block others; success if ≥1 target succeeds
  • Template rendering: target extras support {dot.notation} payload templates (same as deliver_extra today)
  • Startup validation: deliver_only routes with list format must validate every target has a real type (not log)
  • CLI support: hermes webhook subscribe should accept --deliver multiple times

Scope

  ┌──────────────────────────────┬───────────────────────────────────────────────────────┐
  │          Component           │                        Change                         │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ gateway/platforms/webhook.py │ Core multi-target dispatch logic                      │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ hermes_cli/webhook.py        │ CLI --deliver multi-target parsing                    │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ hermes_cli/main.py           │ Argparse --deliver → action="append"                  │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ Tests                        │ New test file for multi-deliver scenarios             │
  ├──────────────────────────────┼───────────────────────────────────────────────────────┤
  │ Docs                         │ Update webhooks.md with Multi-Target Delivery section │
  └──────────────────────────────┴───────────────────────────────────────────────────────┘

Use Cases

  1. PR review + notification: Agent reviews a PR → posts comment on GitHub AND notifies author on Telegram
  2. Alert fan-out: Monitoring webhook fires → push to Slack + Discord + Email simultaneously
  3. Audit trail: Process event → deliver to user chat AND log to an audit channel
  4. Direct delivery fan-out: deliver_only with multi-target for zero-LLM-cost push notifications to multiple channels

Alternatives Considered

  1. New delivers field (plural): Cleaner separation but adds a new top-level field and mutual exclusivity rules. More config surface to document.
  2. Webhook chaining: One route triggers another route. Works but adds latency, complexity, and doesn't reduce agent runs.
  3. External fan-out proxy: User deploys a separate service to duplicate POSTs to multiple routes. Shifts complexity to the user.

Extending deliver to accept both string and list is the simplest path with zero breaking changes.

Feature Type

Configuration option

Scope

Medium (few files, < 300 lines)

Contribution

  • I'd like to implement this myself and submit a PR

Debug Report (optional)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING