/ccc-ci — CI/CD Webhook Channel
Bridges your CI/CD pipeline to your active Claude Code session. Deploy events arrive in real time; failures trigger automatic diagnosis; successes get celebrated.
What it does
/ccc-ci runs a lightweight HTTP receiver on localhost:7891 that accepts signed webhook payloads from GitHub Actions, Vercel, Railway, and Fly.io. Each inbound event is classified, routed to a handler, and surfaced in chat — so you see deploy failures, test results, and approval gates without leaving your session. On failure, CCC automatically loads /ccc-doctor, reads the CI log, classifies the error, and proposes a concrete fix. On success, it drafts a celebration tweet you can post with one click.
Setup
# 1. Start the local receiver (default port 7891)
/ccc-ci init
# 2. (Optional) pick a different port
/ccc-ci init --port 8321
# 3. Expose publicly if your CI provider can't reach localhost
/ccc-ci init --tunnel # wraps with ngrok or cloudflared
init prints a webhook URL, copies it to clipboard, and emits ready-to-paste configs for each supported provider.
GitHub Actions — paste into your workflow YAML
- name: Notify CCC
if: always()
run: |
curl -s -X POST ${{ secrets.CCC_WEBHOOK_URL }} \
-H "X-CCC-Signature: $(echo -n '${{ toJSON(github.event) }}' | openssl dgst -sha256 -hmac '${{ secrets.CCC_SECRET }}' | awk '{print $2}')" \
-H "Content-Type: application/json" \
-d '{"event":"${{ job.status == 'success' && 'deploy_succeeded' || 'deploy_failed' }}","ref":"${{ github.ref }}","run_url":"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}'
Vercel — Dashboard → Settings → Webhooks → Add
Point to the URL printed by /ccc-ci init. Select: deployment.created, deployment.succeeded, deployment.error.
Fly.io — fly webhooks create
fly webhooks create --app myapp \
--url "$(pbpaste)" \
--events instance_state_change
Supported Events
| Event | Trigger |
|---|---|
push |
New commit pushed to any branch |
deploy_started |
Deploy job kicked off |
deploy_failed |
Deploy exited non-zero |
deploy_succeeded |
Deploy completed and healthy |
test_failed |
Test suite reported failures |
test_succeeded |
All tests green |
approval_required |
Manual prod gate waiting |
Auto-actions per event
deploy_failed
- Load
/ccc-doctorin the current session - Read the error log URL from the payload
- Classify: dependency error / OOM / config drift / timeout / unknown
- Propose targeted fix command in chat (copy-paste ready)
test_failed
- Spawn a debugger agent with the error output
- Generate a ranked hypothesis list (most likely root cause first)
- Suggest the minimal reproduction command
deploy_succeeded
- Print deploy stats: duration, provider, environment, URL
- Draft a celebration tweet: "Just shipped X to production in Ys. 🚀 #buildinpublic"
approval_required
- Forward notification to
/ccc-nightwatchso you're alerted even if your session is idle - Print the approval URL and the command to approve via CLI
Architecture
GitHub Actions / Vercel / Fly.io / Railway
│ (HTTPS POST, HMAC-signed)
▼
localhost:7891 ◄── /ccc-ci init (Node http.Server)
│
signature check (HMAC-SHA256)
│ pass │ fail
▼ ▼
event classifier drop + warn
push | deploy_* | test_*
│
session bus (stdout pipe to Claude Code session)
│
skill router
├── deploy_failed → /ccc-doctor + fix proposal
├── test_failed → debugger agent
├── deploy_succeeded → celebration + tweet draft
└── approval_required → /ccc-nightwatch relay
Examples
1 — PR fails CI on TypeScript error
GitHub Actions calls the webhook with test_failed and the log URL. CCC fetches the log, extracts the TS error, and posts: "TS2339 on src/auth.ts:42 — property user does not exist on type Session. Fix: add user?: User to the Session interface."
2 — Vercel deploy preview ready
deploy_succeeded arrives with preview URL. CCC posts: "Preview live → https://my-app-abc123.vercel.app — running Lighthouse... Score: Performance 94, A11y 100, SEO 91."
3 — Fly.io deploy crashes
deploy_failed arrives with instance logs. CCC reads the log, finds OOMKilled, and posts: "Memory limit hit (256MB). Fix: increase [[vm]] memory_mb = 512 in fly.toml, then fly deploy."
Security
- Signature validation: every request is verified with HMAC-SHA256 against a shared secret generated at
inittime and stored in~/.claude/commander/ccc-ci.secret. - Loopback only by default: the receiver binds
127.0.0.1:7891— not reachable from the internet unless--tunnelis passed. - Tunnel exposure:
--tunnellaunchesngrok http 7891orcloudflared tunnel --url http://localhost:7891. The tunnel URL is rotated eachinitrun; update your webhook config accordingly. - Secret rotation: run
/ccc-ci init --rotateto generate a new secret and print updated webhook configs.
When NOT to use
- Solo dev with fully manual deploys and no CI configured
- Monorepo where CI runs are owned by another team — webhook noise without context
- Air-gapped environments where
localhost:7891can never receive external webhooks
Tools used
| Tool | Why |
|---|---|
Bash |
Start the HTTP receiver, validate HMAC, curl CI log URLs |
Read |
Parse .github/workflows/, fly.toml, vercel.json for CI context |
Agent |
Spawn debugger sub-agent on test_failed with error payload |
⚙️ Fable contract: plan before build · verifier ≠ worker · prove before alarm · loops need gates · leave durable state —
rules/fable-method.md