feat(events-shim): self-hosted webhook inboxes that wake idle agents

Merged
KH
3h ago
+1541-11

Summary

Self-hosted events shim (@agent-relay/events-shim): webhook inboxes whose single MCP URL wakes an idle agent on each post — the same API as Cloud, for installs that must keep delivery in their own AWS/GCP/Kubernetes.

  • New feature events_shim in SELFHOST_FEATURES (off by default; all /api/v1/events-shim/* paths 404 when off, including the /cloud alias).
  • Creating an inbox requires a signed-in user (bearer or same-origin cookie; unexchanged handoffs refused), records workspace/user, 20/h per user. Webhook, MCP and manage routes stay capability-token based.
  • Migration 0047_events_shims; raw-SQL store (row-locked seq, idempotent append, pruning, read never re-queued); tokens hashed, secrets encrypted with the keyring; tables in CONTROL_TABLES.
  • Wake allowlist from RELAYCAST_PUBLIC_URL, overridable with SELFHOST_EVENTS_SHIM_RELAY_ORIGINS; URLs from SELFHOST_PUBLIC_URL; 64 KiB bodies; long-poll aborted on disconnect.
  • openapi.yaml, docs/events-shim.md, README, docs/features.md, CHANGELOG.

Depends on @agent-relay/events-shim@18.2.0 (relay release). package-lock.json is refreshed after that release; until then npm ci fails.

Test Plan

  • test/events-shim.test.ts 10/10 (full app on PGlite: signed-in create → MCP watch/link → forwarded wake → woken; broken link fallback; wait_for_webhook; auth refusal; rotate; idempotency; bearer secret encrypted at rest; 413; workspace delete cascade; feature off 404; origins validation)
  • Full npm test: 1221 tests, 1208 pass, 0 fail
  • npm run typecheck clean
  • Package verified end to end against real Relaycast + Agent Relay Desktop (see AgentWorkforce/relay#2151)

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds a self-hosted webhook inbox that stores posts and wakes an idle agent through its Agent Relay session webhook, with MCP long-polling as a fallback.

  • Enable with SELFHOST_FEATURES=events_shim; routes return 404 before authentication while disabled.
  • Creating an inbox requires a signed-in person and is limited to 20 per hour; webhook, MCP, and management routes use capability tokens. Verified modes (GitHub, Stripe, Linear) check the sender's body signature; bearer checks a shared token.
  • Migration 0047 adds the inbox, post, event, and idempotency tables; tokens are hashed and secrets encrypted with the keyring.
  • Row-locked quotas and appends prevent concurrent overages; deduplication survives feed pruning, claims avoid duplicate delivery, and a sending lease expires so a dead sender never strands a post.
  • Posts are acknowledged before their wake is forwarded; wake results apply only to the sender's own claim, so an expired sender cannot confirm or release a post another sender has re-claimed — delivery state only moves forward.
  • Removing the creator from their workspace's organization disables their inbox URLs; wake targets are restricted to configured Relaycast origins.
  • Request bodies are capped at 64 KiB (chunked transfers included), and long-polls abort on disconnect.
  • Depends on @agent-relay/events-shim@18.2.0, now locked in package-lock.json.