Files
joelhooks__joelclaw/docs/webhooks.md

3.4 KiB

Webhooks

Canonical notes for the webhook gateway and subscription dispatch path.

HTTP gateway

  • server: packages/system-bus/src/webhooks/server.ts
  • endpoint: POST /webhooks/:provider
  • providers:
    • todoist
    • front
    • vercel
    • github
    • mux
    • joelclaw

Contract:

  1. Verify provider signature from raw request body.
  2. Normalize payload into typed internal events.
  3. By default, emit to Inngest as <provider>/<event>.
  4. Queue pilots may intercept specific normalized events first, persist them into the shared Redis queue, and let the Restate drainer forward the concrete Inngest event name.

Health-check contract:

  • system health probes should hit GET /webhooks through the shared endpoint resolver (localhost -> Colima VM IP -> service DNS) rather than assuming the host-worker localhost path is the only valid surface.
  • a fast 401 Invalid signature on POST /webhooks/:provider is healthy behavior for unauthenticated probes; it proves the route is alive and signature enforcement is working.

GitHub workflow path

  • provider adapter: packages/system-bus/src/webhooks/providers/github.ts
  • normalized event: github/workflow_run.completed
  • payload includes:
    • deliveryId
    • workflow + run metadata (runId, workflowName, branch, conclusion, etc.)
  • pilot cutover:
    • default path still emits directly to Inngest
    • when QUEUE_PILOTS=github, workflow_run.completed is enqueued into the shared queue first and the Restate drainer forwards the exact Inngest event name github/workflow_run.completed
    • github/package.published stays on the legacy direct path for now

Session-scoped webhook subscriptions (ADR-0185)

Redis keys:

  • joelclaw:webhook:subscriptions (hash: id -> subscription json)
  • joelclaw:webhook:index:<provider>:<event> (set of subscription IDs)
  • joelclaw:webhook:events:<subscription-id> (replay list)
  • joelclaw:webhook:notify:<subscription-id> (pub/sub channel)
  • joelclaw:webhook:dedup:<subscription-id>:<delivery-key> (idempotency)

Runtime requirement (cluster worker):

  • REDIS_HOST=redis
  • REDIS_PORT=6379
  • configured in k8s/system-bus-worker.yaml

CLI surface:

joelclaw webhook subscribe github workflow_run.completed --repo joelhooks/joelclaw --stream
joelclaw webhook list
joelclaw webhook stream <subscription-id>
joelclaw webhook unsubscribe <subscription-id>

Dispatch function

  • function: webhook-subscription-dispatch-github-workflow-run-completed
  • file: packages/system-bus/src/inngest/functions/webhook-subscription-dispatch.ts
  • trigger: github/workflow_run.completed

Behavior:

  1. Match active subscriptions for github/workflow_run.completed.
  2. Prune expired/invalid subscriptions from Redis.
  3. Best-effort fetch GitHub workflow artifacts.
  4. Deduplicate delivery per subscription.
  5. Fan out matched payload to subscription replay list + notify channel.
  6. Push webhook.subscription.matched to gateway routing with originSession for immediate follow-up turn.

Verification

# create + stream
joelclaw webhook subscribe github workflow_run.completed \
  --repo joelhooks/joelclaw --workflow CI --conclusion success --stream --timeout 30

# inspect subscriptions
joelclaw webhook list

# stream existing subscription
joelclaw webhook stream <subscription-id> --timeout 30 --replay 10

# remove subscription
joelclaw webhook unsubscribe <subscription-id>