feat(events-shim): self-hosted webhook inboxes that wake idle agents
Merged
KH
3h ago+1541+1541+0123456789012345678901234567890123456789-11-11-01234567890123456789
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_shiminSELFHOST_FEATURES(off by default; all/api/v1/events-shim/*paths 404 when off, including the/cloudalias). - 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,
readnever re-queued); tokens hashed, secrets encrypted with the keyring; tables inCONTROL_TABLES. - Wake allowlist from
RELAYCAST_PUBLIC_URL, overridable withSELFHOST_EVENTS_SHIM_RELAY_ORIGINS; URLs fromSELFHOST_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.ts10/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 typecheckclean - Package verified end to end against real Relaycast + Agent Relay Desktop (see AgentWorkforce/relay#2151)
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
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
sendinglease 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 inpackage-lock.json.