Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implement CodeRabbit webhook signature validation and event handling. Use when setting up webhook endpoints, implementing signature verification, or handling CodeRabbit event notifications securely. Trigger with phrases like "coderabbit webhook", "coderabbit events", "coderabbit webhook signature", "handle coderabbit events", "coderabbit notifications".
.claude/skills/jeremylongshore-coderabbit-webhooks-events/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 75% | 4 |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | -8% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 42% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 16% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 37% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 40% | 0% |
Handle CodeRabbit events triggered through GitHub and GitLab integrations. CodeRabbit posts AI-powered code review comments on pull requests.
.coderabbit.yaml configuration in repository root| Event | Source | Payload | |-------|--------|---------| | pull_request_review | GitHub webhook | Review body, state (approved/changes_requested) | | pull_request_review_comment | GitHub webhook | Line comment, diff position, file path | | check_run.completed | GitHub Checks API | CodeRabbit analysis results, conclusion | | issue_comment.created | GitHub webhook | Summary comment, walkthrough | | pull_request.labeled | GitHub webhook | Labels applied by CodeRabbit |
typescriptimport express from "express"; import crypto from "crypto"; const app = express(); app.post("/webhooks/github", express.raw({ type: "application/json" }), async (req, res) => { const signature = req.headers["x-hub-signature-256"] as string; # 256 bytes const secret = process.env.GITHUB_WEBHOOK_SECRET!; const expected = "sha256=" + crypto .createHmac("sha256", secret) .update(req.body) .digest("hex"); if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) { return res.status(401).json({ error: "Invalid signature" }); # HTTP 401 Unauthorized } const event = req.headers["x-github-event"] as string; const payload = JSON.parse(req.body.toString()); res.status(200).json({ received: true }); # HTTP 200 OK await routeCodeRabbitEvent(event, payload); } );
typescriptasync function routeCodeRabbitEvent(event: string, payload: any) { const isCodeRabbit = payload?.sender?.login === "coderabbitai[bot]"; if (!isCodeRabbit && event !== "check_run") return; switch (event) { case "pull_request_review": await handleCodeRabbitReview(payload); break; case "pull_request_review_comment": await handleReviewComment(payload); break; case "check_run": if (payload.check_run?.app?.slug === "coderabbitai") { await handleCheckRunComplete(payload); } break; case "issue_comment": await handleSummaryComment(payload); break; } }
typescriptasync function handleCodeRabbitReview(payload: any) { const { review, pull_request } = payload; const prNumber = pull_request.number; const state = review.state; if (state === "changes_requested") { const issues = parseReviewIssues(review.body); await notifyTeam({ channel: "#code-reviews", message: `CodeRabbit found ${issues.length} issues in PR #${prNumber}`, prUrl: pull_request.html_url, }); } if (state === "approved") { await checkAutoMergeEligibility(prNumber); } } function parseReviewIssues(body: string): string[] { return body.split("\n").filter(line => line.match(/^[-*]\s+(Bug|Issue|Suggestion|Security)/i) ); }
yaml# .coderabbit.yaml reviews: auto_review: enabled: true drafts: false path_filters: - "!**/*.test.ts" - "!**/generated/**" review_instructions: - path: "src/api/**" instructions: "Focus on security and input validation" chat: auto_reply: true
| Issue | Cause | Solution | |-------|-------|----------| | No review posted | PR too large | Split PR or adjust max_files in config | | Invalid signature | Wrong GitHub secret | Verify webhook secret in App settings | | Bot not responding | App not installed | Check CodeRabbit GitHub App installation | | Duplicate comments | Re-triggered workflow | CodeRabbit deduplicates automatically |
typescriptasync function handleCheckRunComplete(payload: any) { const { check_run } = payload; await metricsDb.insert({ prNumber: check_run.pull_requests?.[0]?.number, conclusion: check_run.conclusion, issuesFound: check_run.output?.annotations_count || 0, completedAt: check_run.completed_at, }); }
For deployment setup, see coderabbit-deploy-integration.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 16,284 | 11,097 | -32% | 1 | 1 | 0% | 3,403 | 3,743 | +10% | 0 | 0 | — |
case-02 | fail→fail | 19,720 | 15,954 | -19% | 1 | 1 | 0% | 4,264 | 4,921 | +15% | 0 | 0 | — |
case-03 | pass→pass | 12,785 | 8,893 | -30% | 1 | 1 | 0% | 2,822 | 3,255 | +15% | 0 | 0 | — |
case-04 | pass→pass | 10,741 | 7,785 | -28% | 1 | 1 | 0% | 2,095 | 2,932 | +40% | 0 | 0 | — |
case-05 | fail→pass | 13,655 | 5,349 | -61% | 1 | 1 | 0% | 2,679 | 2,456 | -8% | 0 | 0 | — |
case-06 | fail→pass | 7,687 | 4,410 | -43% | 1 | 1 | 0% | 1,449 | 2,052 | +42% | 0 | 0 | — |
case-07 | pass→pass | 6,102 | 2,797 | -54% | 1 | 1 | 0% | 1,125 | 1,805 | +60% | 0 | 0 | — |
case-08 | fail→pass | 8,344 | 2,285 | -73% | 1 | 1 | 0% | 1,540 | 1,781 | +16% | 0 | 0 | — |
case-09 | pass→pass | 9,259 | 3,788 | -59% | 1 | 1 | 0% | 1,817 | 2,098 | +15% | 0 | 0 | — |
case-10 | pass→pass | 13,597 | 5,168 | -62% | 1 | 1 | 0% | 2,297 | 2,223 | -3% | 0 | 0 | — |
case-15 | fail→pass | 7,236 | 2,977 | -59% | 1 | 1 | 0% | 1,314 | 1,803 | +37% | 0 | 0 | — |
case-11 | fail→pass | 13,261 | 9,073 | -32% | 1 | 1 | 0% | 2,156 | 3,009 | +40% | 0 | 0 | — |
case-12 | pass→pass | 10,551 | 7,619 | -28% | 1 | 1 | 0% | 1,852 | 2,766 | +49% | 0 | 0 | — |
case-13 | fail→pass | 11,666 | 6,625 | -43% | 1 | 1 | 0% | 2,200 | 2,536 | +15% | 0 | 0 | — |
case-14 | pass→pass | 4,197 | 2,429 | -42% | 1 | 1 | 0% | 746 | 1,737 | +133% | 0 | 0 | — |
case-16 | pass→pass | 3,271 | 2,117 | -35% | 1 | 1 | 0% | 534 | 1,706 | +219% | 0 | 0 | — |
case-17 | fail→pass | 10,317 | 2,655 | -74% | 1 | 1 | 0% | 1,764 | 1,875 | +6% | 0 | 0 | — |
case-18 | fail→pass | 11,640 | 12,719 | +9% | 1 | 1 | 0% | 2,472 | 3,728 | +51% | 0 | 0 | — |
case-19 | fail→pass | 8,551 | 4,693 | -45% | 1 | 1 | 0% | 1,440 | 2,203 | +53% | 0 | 0 | — |
case-20 | pass→pass | 5,112 | 4,217 | -18% | 1 | 1 | 0% | 1,077 | 2,169 | +101% | 0 | 0 | — |
case-21 | pass→pass | 7,358 | 5,047 | -31% | 1 | 1 | 0% | 1,425 | 2,304 | +62% | 0 | 0 | — |
case-22 | pass→pass | 9,580 | 6,840 | -29% | 1 | 1 | 0% | 1,976 | 2,745 | +39% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +41 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.