Skip to content

Pipeline Plan 23

Seth Ford edited this page Feb 11, 2026 · 2 revisions

The plan has been fully developed. Here's the implementation plan:


Plan: Add Webhook Receiver for Instant Issue Processing

Architecture Overview

The webhook system bridges GitHub's push-based events with Shipwright's existing poll-based daemon. The dashboard server (Bun/TypeScript) receives GitHub webhook POSTs at /api/webhook/github, validates HMAC-SHA256 signatures, and writes validated issues.labeled events to a trigger file. The daemon's poll loop detects trigger files and runs an immediate poll, reducing latency from 0-30s to sub-second. Polling remains as the fallback when webhooks aren't configured.

Key design decision: The dashboard already runs an HTTP server with the /api/webhook/ci pattern. Adding /api/webhook/github here avoids a separate server. Daemon-dashboard communication uses the filesystem (same pattern as daemon-pause.flag).

Files to Modify

File Action Purpose
scripts/sw-webhook-test.sh Create Test suite for webhook trigger handling + CLI flag
dashboard/server.ts Modify Add /api/webhook/github + /api/webhook/status endpoints
scripts/sw-daemon.sh Modify Trigger file detection, --webhook flag, config loading
scripts/sw-daemon-test.sh Modify Add webhook config + trigger tests
.claude/CLAUDE.md Modify Document webhook configuration

Implementation Steps

  1. Daemon config schema — Add webhook.secret and webhook.dashboard_url to load_config() (line ~362) and defaults (line ~207)
  2. Init template — Add "webhook": { "secret": null, "dashboard_url": null } to daemon_init() heredoc (line ~4521)
  3. daemon init --webhook — New daemon_init_webhook() function: generates secret via openssl rand -hex 32, creates GitHub webhook via gh api repos/{owner}/{repo}/hooks, writes secret to config
  4. HMAC validationvalidateWebhookSignature() in server.ts using Web Crypto API with constant-time comparison
  5. POST /api/webhook/github — Public endpoint: validate signature, filter issues.labeled events matching watch_label, write trigger file to ~/.shipwright/webhook-triggers/<issue>.json, log delivery, broadcast to WS
  6. GET /api/webhook/status — Protected endpoint returning delivery history and stats from webhook-deliveries.jsonl
  7. FleetState webhook field — Add webhook to FleetState interface, populate from delivery log in getFleetState()
  8. daemon_check_webhook_triggers() — Checks ~/.shipwright/webhook-triggers/ for files, removes them, calls daemon_poll_issues
  9. Poll loop integration — Call trigger check every second inside the existing 1-second sleep loop (line ~4197)
  10. Test suitesw-webhook-test.sh + additions to sw-daemon-test.sh
  11. Help text + docs — Update show_help(), CLAUDE.md, register test in package.json
  12. Run npm test — Ensure all 22+ test suites pass

Task Checklist (13 tasks)

  • Task 1: Add webhook config fields to load_config() and defaults
  • Task 2: Add webhook section to daemon_init() generated config
  • Task 3: Implement daemon_init_webhook() + --webhook CLI flag
  • Task 4: Add HMAC-SHA256 validation function in server.ts
  • Task 5: Implement POST /api/webhook/github endpoint
  • Task 6: Implement GET /api/webhook/status endpoint
  • Task 7: Add webhook to FleetState interface + getFleetState()
  • Task 8: Implement daemon_check_webhook_triggers() in sw-daemon.sh
  • Task 9: Integrate trigger checking into daemon poll loop sleep
  • Task 10: Create scripts/sw-webhook-test.sh
  • Task 11: Add webhook tests to sw-daemon-test.sh
  • Task 12: Update help text, CLAUDE.md, package.json
  • Task 13: Run full test suite and fix failures

Definition of Done

  • /api/webhook/github accepts GitHub webhook payloads with HMAC-SHA256 validation
  • issues.labeled events matching watch_label trigger instant daemon polling (< 1s)
  • Polling continues as fallback when webhook is not configured
  • shipwright daemon init --webhook auto-configures GitHub webhook via gh api
  • /api/webhook/status shows delivery history and latency
  • New test suite passes + all 22 existing suites pass
  • Bash 3.2 compatible throughout

Clone this wiki locally