Setup and context — Why Automate Production Quality Now
For solo developers and small teams, production incident response quietly consumes enormous amounts of time. Late-night alerts, morning bug reports, digging through stack traces, pinpointing root causes, writing fixes, running tests, and deploying — when you're doing all of this manually, your ability to ship new features suffers.
Antigravity, used as an AI agent, can automate the majority of this cycle. This article walks you through building a three-layer quality automation pipeline using Sentry (error tracking) and GitHub Actions (CI/CD), complete with real code examples.
This guide is written for developers who:
- Want to take their Antigravity automation beyond basic code generation
- Are ready to move from manual incident response to automated remediation
- Want to reduce MTTR and reclaim development time for actual product work
For a primer on AI-assisted unit test generation, see Antigravity × Vitest: AI-Powered Unit Test Generation in Practice.
Pipeline Architecture Overview
The pipeline we're building consists of three distinct layers.
Layer 1: Detection
Sentry captures production errors and performance degradation in real time. Events that exceed configured thresholds are forwarded to the next layer via webhook.
Layer 2: Analysis
A GitHub Actions workflow receives the Sentry event and calls the Antigravity CLI. The Antigravity agent cross-references the stack trace, relevant source code, and recent commit diffs to identify root causes and generate a proposed fix.
Layer 3: Remediation
A Pull Request containing the AI-generated fix is automatically created. The PR includes a summary of the error, root cause analysis, a description of the fix, and added test cases.
Sentry (Error / Alert)
↓
Webhook → GitHub Actions Trigger
↓
Antigravity CLI (Analysis Agent)
├─ Stack trace analysis
├─ Related code extraction (git blame + Antigravity context)
└─ Fix code generation
↓
GitHub PR (auto-created)
├─ Code diff with fix
├─ Added test cases
└─ Root cause analysis report
Step 1: Sentry Setup and Webhook Configuration
Start by configuring Sentry and setting up the webhook that triggers GitHub Actions.
1-1. Installing the Sentry SDK
Using a Next.js project as our example:
npm install @sentry/nextjs
npx @sentry/wizard@latest -i nextjsConfigure sentry.client.config.ts:
// sentry.client.config.ts
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
integrations: [
Sentry.replayIntegration({
maskAllText: false,
blockAllMedia: false,
}),
],
// 10% session sampling in production, 100% on error
replaysSessionSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1.0,
replaysOnErrorSampleRate: 1.0,
});1-2. Configuring Sentry Alert Rules
In the Sentry dashboard, navigate to Alerts → Create Alert Rule and set:
- Trigger:
Number of errors in 5 minutes > 5 - Action:
Send a notification via webhook - Webhook URL: Your bridge endpoint (see below)
1-3. Building the Sentry → GitHub Actions Bridge
Rather than calling GitHub's repository_dispatch endpoint directly (which requires auth headers that Sentry can't set), use a lightweight Cloudflare Worker as a bridge:
// cloudflare-worker: sentry-to-github-bridge.js
export default {
async fetch(request, env) {
if (request.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
const body = await request.json();
// Verify Sentry signature
const sentrySignature = request.headers.get("sentry-hook-signature");
if (!verifySentrySignature(body, sentrySignature, env.SENTRY_WEBHOOK_SECRET)) {
return new Response("Unauthorized", { status: 401 });
}
// Trigger GitHub repository_dispatch
const githubResponse = await fetch(
`https://api.github.com/repos/${env.GITHUB_OWNER}/${env.GITHUB_REPO}/dispatches`,
{
method: "POST",
headers: {
Authorization: `token ${env.GITHUB_TOKEN}`,
Accept: "application/vnd.github.v3+json",
"Content-Type": "application/json",
},
body: JSON.stringify({
event_type: "sentry-error-alert",
client_payload: {
issue_id: body.data?.issue?.id,
issue_url: body.data?.issue?.web_url,
title: body.data?.issue?.title,
culprit: body.data?.issue?.culprit,
stack_trace: body.data?.issue?.exception?.values?.[0]?.stacktrace,
level: body.data?.issue?.level,
},
}),
}
);
return new Response(JSON.stringify({ status: "dispatched" }), {
headers: { "Content-Type": "application/json" },
});
},
};
function verifySentrySignature(body, signature, secret) {
// Implement HMAC-SHA256 verification in production
return !!signature;
}Step 2: GitHub Actions Workflow
Create the workflow that receives Sentry triggers and drives the Antigravity analysis agent:
# .github/workflows/ai-quality-fix.yml
name: AI Quality Auto-Fix
on:
repository_dispatch:
types: [sentry-error-alert]
permissions:
contents: write
pull-requests: write
jobs:
analyze-and-fix:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 50 # Required for recent commit diff analysis
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Install Antigravity CLI
run: npm install -g @antigravity/cli
- name: Extract error context
id: error-context
run: |
echo "ISSUE_ID=${{ github.event.client_payload.issue_id }}" >> $GITHUB_ENV
echo '${{ toJson(github.event.client_payload.stack_trace) }}' > /tmp/stack_trace.json
- name: Fetch detailed Sentry data
run: |
curl -s "https://sentry.io/api/0/issues/${{ github.event.client_payload.issue_id }}/" \
-H "Authorization: Bearer ${{ secrets.SENTRY_AUTH_TOKEN }}" \
> /tmp/sentry_issue.json
curl -s "https://sentry.io/api/0/issues/${{ github.event.client_payload.issue_id }}/events/latest/" \
-H "Authorization: Bearer ${{ secrets.SENTRY_AUTH_TOKEN }}" \
> /tmp/sentry_event.json
- name: Run Antigravity Analysis Agent
env:
ANTIGRAVITY_API_KEY: ${{ secrets.ANTIGRAVITY_API_KEY }}
run: |
antigravity run --non-interactive \
--model gemini-3.1-pro \
--max-turns 20 \
--output /tmp/analysis_result.json \
"Analyze the following production error and generate a fix.
Error title: $(cat /tmp/sentry_issue.json | jq -r '.title')
Culprit: $(cat /tmp/sentry_issue.json | jq -r '.culprit')
Stack trace:
$(cat /tmp/sentry_event.json | jq -r '.entries[] | select(.type==\"exception\") | .data.values[0].stacktrace.frames[] | \"\(.filename):\(.lineNo) in \(.function)\"' | head -20)
Tasks:
1. Identify the root cause of the error
2. Generate a fix (all existing tests must continue to pass)
3. Add 1-2 regression test cases to prevent recurrence
4. Summarize the fix in one clear sentence
Save the git diff to /tmp/fix_diff.patch when done."
- name: Apply fix and create PR
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH_NAME="ai-fix/sentry-${{ github.event.client_payload.issue_id }}-$(date +%Y%m%d%H%M)"
git checkout -b "$BRANCH_NAME"
if [ -f /tmp/fix_diff.patch ]; then
git apply /tmp/fix_diff.patch || echo "Patch apply failed — manual review needed"
fi
git add -A
git commit -m "fix: auto-fix for Sentry issue #${{ github.event.client_payload.issue_id }}
$(cat /tmp/analysis_result.json | jq -r '.summary // "Automated fix for Sentry error"')
Sentry Issue: ${{ github.event.client_payload.issue_url }}"
git push origin "$BRANCH_NAME"
gh pr create \
--title "🤖 AI Fix: ${{ github.event.client_payload.title }}" \
--body "## Summary
This PR was automatically generated by Antigravity AI after Sentry detected a production error.
## Error Details
- **Issue URL**: ${{ github.event.client_payload.issue_url }}
- **Level**: ${{ github.event.client_payload.level }}
- **Culprit**: ${{ github.event.client_payload.culprit }}
## AI Analysis
$(cat /tmp/analysis_result.json | jq -r '.analysis // "No analysis available"')
## Fix Description
$(cat /tmp/analysis_result.json | jq -r '.fix_description // "No description available"')
## ⚠️ Review Checklist
This PR was AI-generated. Before merging, verify:
- [ ] The fix logic is correct
- [ ] Added tests are meaningful
- [ ] No unintended side effects
🤖 Generated by Antigravity Quality Auto-Fix Pipeline" \
--base main \
--head "$BRANCH_NAME"Within minutes of a Sentry alert firing, a fix candidate PR is automatically available for review.
Step 3: Optimizing Antigravity's Analysis Prompts
The quality of Antigravity's prompt directly determines the accuracy of the automated fix. Here's how to sharpen it beyond the basics.
Embedding Quality Policy in AGENTS.md
Add quality policies to AGENTS.md so Antigravity has project-specific context when generating fixes:
# AGENTS.md — Error Handling Policy
When fixing production errors:
1. **Root cause first**: Identify WHY the error occurred, not just WHERE.
2. **Defensive coding**: Add null checks, type guards, and boundary validation.
3. **Test coverage**: Every bug fix must include a regression test.
4. **No silent failures**: Replace empty `catch` blocks with proper error logging.
5. **Sentry reporting**: Use `Sentry.captureException(error, { extra: context })` for non-fatal errors.
## Code Quality Standards
- TypeScript strict mode is enforced
- All async functions must handle rejection
- API responses must be validated with Zod schemas before use
- Database queries must use parameterized statementsDynamic Prompts by Error Severity
Tailoring the analysis prompt to error severity improves fix accuracy:
# analyze-error.sh
#!/bin/bash
ERROR_LEVEL="${1:-error}"
ERROR_CULPRIT="${2}"
STACK_TRACE="${3}"
case "$ERROR_LEVEL" in
"fatal")
URGENCY="Critical (potential service outage)"
FOCUS="Prioritize immediately deployable code changes. Propose architectural changes separately."
;;
"error")
URGENCY="High priority"
FOCUS="Fix root cause and add regression tests."
;;
"warning")
URGENCY="Medium priority"
FOCUS="Performance improvement or preventive fix for potential bug."
;;
esac
antigravity run --non-interactive \
--model gemini-3.1-pro \
"Urgency: ${URGENCY}
Error location: ${ERROR_CULPRIT}
Stack trace:
${STACK_TRACE}
Analysis focus: ${FOCUS}
Output as JSON:
{
\"root_cause\": \"Root cause in 1-2 sentences\",
\"affected_files\": [\"file paths\"],
\"fix_strategy\": \"Fix approach in 3-5 sentences\",
\"code_changes\": [{ \"file\": \"\", \"before\": \"\", \"after\": \"\" }],
\"test_additions\": [{ \"file\": \"\", \"test_code\": \"\" }],
\"risk_level\": \"low|medium|high\"
}"Step 4: Integrating Performance Monitoring
Beyond error tracking, you can also detect and analyze performance regressions automatically.
Tracking Web Vitals with Sentry
// src/lib/monitoring.ts
import * as Sentry from "@sentry/nextjs";
export function reportWebVitals(metric: NextWebVitalsMetric) {
const { name, value, id } = metric;
Sentry.addBreadcrumb({
category: "web-vitals",
message: `${name}: ${Math.round(value)}`,
level: "info",
data: { id, value: Math.round(value) },
});
const thresholds: Record<string, number> = {
LCP: 2500,
FID: 100,
CLS: 0.1,
TTFB: 800,
FCP: 1800,
};
if (thresholds[name] && value > thresholds[name]) {
Sentry.captureMessage(`Performance degradation: ${name} = ${value}ms`, {
level: "warning",
tags: { metric: name, page: window.location.pathname },
extra: { threshold: thresholds[name], actual: value },
});
}
}Antigravity Performance Analysis Prompt
Performance issues warrant a different analysis prompt than errors:
antigravity run --non-interactive \
--model gemini-3.1-pro \
"Analyze the following performance regression.
Page: ${AFFECTED_PAGE}
Metric: ${METRIC_NAME} = ${METRIC_VALUE}ms (threshold: ${THRESHOLD}ms)
Period: ${START_TIME} to ${END_TIME}
Investigate:
- The affected page component (src/app/${PAGE_PATH}/page.tsx)
- Commits in the past 72 hours (git log --oneline -20)
- Bundle size changes
Output:
1. Probable cause of the regression
2. Code changes to improve performance
3. Expected improvement (estimated ms reduction)"Step 5: Test Failure Auto-Fix Integration
Add automatic analysis and fix generation for CI test failures:
# .github/workflows/test-failure-auto-fix.yml
name: Auto-Fix Test Failures
on:
workflow_run:
workflows: ["CI Tests"]
types: [completed]
jobs:
analyze-failure:
if: github.event.workflow_run.conclusion == 'failure'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download test results
uses: actions/download-artifact@v4
with:
name: test-results
path: /tmp/test-results
- name: Analyze with Antigravity
env:
ANTIGRAVITY_API_KEY: ${{ secrets.ANTIGRAVITY_API_KEY }}
run: |
FAILED_TESTS=$(cat /tmp/test-results/junit.xml | python3 -c "
import sys, xml.etree.ElementTree as ET
tree = ET.parse(sys.stdin)
failures = []
for tc in tree.findall('.//testcase[failure]'):
failures.append(f\"{tc.get('classname')}.{tc.get('name')}: {tc.find('failure').text[:200]}\")
print('\n'.join(failures[:10]))
")
antigravity run --non-interactive \
--model gemini-3.1-pro \
"The following tests failed in CI. Fix the source code without deleting any tests.
Failed tests:
${FAILED_TESTS}
Recent commits: $(git log --oneline -5)
When done, save the fix as a git diff to /tmp/test_fix.patch."Step 6: Notifications and Metrics Dashboard
Slack Notifications
- name: Notify Slack
if: always()
uses: slackapi/slack-github-action@v1.26.0
with:
payload: |
{
"text": "${{ job.status == 'success' && '✅' || '❌' }} AI Auto-Fix: ${{ github.event.client_payload.title }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*${{ job.status == 'success' && '✅ Fix PR ready for review' || '❌ Auto-fix failed — manual intervention needed' }}*\n\nSentry Issue: ${{ github.event.client_payload.issue_url }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOKWeekly Pipeline Metrics
#!/bin/bash
# scripts/quality-metrics.sh
echo "=== Quality Auto-Fix Pipeline — Last 7 Days ==="
AUTO_PRS=$(gh pr list --label "ai-auto-fix" --state all --json createdAt \
--jq "[.[] | select(.createdAt > \"$(date -d '7 days ago' --iso-8601)\")]| length" 2>/dev/null || echo "N/A")
MERGED=$(gh pr list --label "ai-auto-fix" --state merged --json mergedAt \
--jq "[.[] | select(.mergedAt > \"$(date -d '7 days ago' --iso-8601)\")]| length" 2>/dev/null || echo "N/A")
echo "Auto-generated PRs: ${AUTO_PRS}"
echo "Merged PRs: ${MERGED}"
echo "Merge rate: $(echo "scale=0; $MERGED * 100 / ($AUTO_PRS + 1)" | bc)%"Common Issues and Solutions
Antigravity fails to identify the correct file from the stack trace
This usually means source maps are not enabled. Add the following to next.config.ts:
const nextConfig: NextConfig = {
productionBrowserSourceMaps: true,
};Also configure source map artifact uploads in Sentry under Project Settings → Source Maps.
Auto-generated PR merge rate is low
Antigravity likely lacks sufficient project context. Improve AGENTS.md with more detailed quality policies, increase --max-turns to allow deeper analysis, and ensure environment differences between production and development are documented.
GitHub Actions costs are running high
Tune your Sentry alert rules to reduce noise. Raise error thresholds (e.g., require more than 5 errors in 5 minutes) and add deduplication logic to prevent the same issue from re-triggering the workflow before it's resolved.
Summary
In this guide, we built a three-layer production quality automation pipeline combining Antigravity, Sentry, and GitHub Actions.
The key components are: Sentry for real-time production error and performance monitoring, Antigravity CLI for root cause analysis and fix code generation, and GitHub Actions for automated PR creation and team notification.
With this pipeline running, you dramatically reduce the time from "error detected" to "fix merged," freeing yourself to focus on building features rather than fighting fires.