Commit Graph

3 Commits

Author SHA1 Message Date
Teknium 5b4d20b524 fix(hooks): flush outbound queue at interpreter exit
The delivery worker is a daemon thread, so a short-lived process
(hermes chat -q, a cron session) could exit right after firing
on_session_end — silently dropping the headline event. Register a
bounded atexit flush (5s) when the worker starts: a dead endpoint can
delay exit slightly, never hang it.

Live-verified: hermes chat -q now delivers on_session_start,
post_tool_call, and on_session_end to a real receiver; regression test
runs a subprocess that exits without flushing (sabotage-verified).
2026-08-02 15:01:11 -07:00
Teknium 86fd6da1dc fix(hooks): single delivery_id across header+body, never follow redirects
- delivery_id is now generated once per firing and used for both the
  X-Hermes-Delivery header and the signed body's delivery_id field —
  previously they were two different uuid4s, breaking receiver-side
  dedupe as documented.
- 3xx responses are no longer followed: urllib's default redirect
  handler converts a redirected POST into a body-less GET, silently
  dropping the signed payload. Redirects now log a misconfiguration
  warning and count as delivery failure (no retry).
- Docs: receiver-side replay-protection guidance (dedupe on
  delivery_id, timestamp freshness window) + redirect semantics.
- Tests: 5xx retry count, redirect-not-followed (sabotage-verified),
  header/body delivery_id equality.
2026-08-02 15:01:11 -07:00
Teknium 3829e34e23 feat(hooks): outbound webhooks — push signed lifecycle events to external HTTP endpoints
The inverse of the inbound webhook platform: hooks.outbound in
config.yaml lists HTTP targets + the plugin-hook events they subscribe
to (on_session_end, subagent_stop, post_tool_call, ...). Each firing
POSTs a JSON payload (same top-level shape as shell hooks' stdin wire)
signed GitHub-style with HMAC-SHA256 (X-Hermes-Signature-256).

Rides the existing hook bus — notify-only callbacks registered on the
plugin manager at the same CLI/gateway/main entry points as shell
hooks. Delivery is fire-and-forget via a bounded queue + single daemon
worker thread, so a dead endpoint can never stall a tool call. Bounded
retries (5xx/conn errors once; 4xx never). secret_env preferred over
inline secret. HERMES_SAFE_MODE skips registration. hermes hooks list
shows outbound targets with signed/UNSIGNED status.

Zero new model tools, zero new subsystems.
2026-08-02 15:01:11 -07:00