AI in the Go CI/CD Pipeline: Quality Gates, Auto Review, Architecture Check
Integrate AI tools into the Golang CI/CD pipeline. Pre-commit AI review, GitHub Actions quality gates, architecture enforcement, and AI-generated PR descriptions for Go.
AI Tools in the Golang CI/CD Pipeline
Integrating AI tools into the Golang CI/CD pipeline unlocks a class of quality gate that ordinary static analysis cannot reach. AI tools are useful not only while a developer is coding — but also in the pipeline for smarter checks. This article shows how to integrate AI into a Go pipeline in a practical, cost-effective way, from the pre-commit hook to the release notes.
18.1 CI/CD Stages That Benefit from AI
Not every stage of the pipeline needs AI. The map below marks the five stages that most clearly gain value from AI along with their estimated cost.
1Pipeline stages where AI provides clear value:
2
3Stage 1: Pre-commit (local, before push)
4 - Quick AI review via a cheap model (haiku)
5 - Architecture violation check
6 - Secret detection
7 Cost: < $0.001 per commit
8
9Stage 2: Pull Request (GitHub Actions)
10 - Copilot automated PR review (built-in if you have Copilot)
11 - Spec compliance audit
12 - AI-generated PR description
13 Cost: $0.001-0.01 per PR
14
15Stage 3: Build & Test
16 - Test failure AI analysis (only if failure)
17 - Coverage gap identification
18 Cost: $0 if it passes, minimal if it fails
19
20Stage 4: Code Quality Gates
21 - Architecture enforcement (Go script, no AI cost)
22 - Complexity analysis
23 Cost: $0 (static analysis)
24
25Stage 5: Post-merge / Deployment
26 - AI-generated release notes
27 - Deployment notes generator
28 Cost: < $0.01 per deploymentThis map reinforces the cost principle: AI is used only at points that add judgment (review, failure analysis), while mechanical enforcement is still handled by free static analysis.
18.2 Pre-commit Hook with AI Review
The cheapest intervention point is before the code is even pushed. The hook below runs a quick review with the haiku model against the staged diff and blocks the commit if there’s a CRITICAL issue.
1#!/bin/bash
2# .git/hooks/pre-commit
3# Quick AI review before commit
4
5set -e
6
7# Only check Go files
8CHANGED_GO=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$' || true)
9
10if [ -z "$CHANGED_GO" ]; then
11 exit 0 # No Go changes, skip
12fi
13
14echo "Running pre-commit AI review..."
15
16# Collect the diff from all changed files
17DIFF=$(echo "$CHANGED_GO" | while read -r file; do
18 git diff --cached "$file"
19done)
20
21if [ -z "$DIFF" ]; then
22 exit 0
23fi
24
25# Call the Claude API (haiku = cheap and fast)
26REVIEW=$(curl -sf -X POST https://api.anthropic.com/v1/messages \
27 -H "x-api-key: ${ANTHROPIC_API_KEY}" \
28 -H "anthropic-version: 2023-06-01" \
29 -H "content-type: application/json" \
30 -d "$(jq -n \
31 --arg diff "$DIFF" \
32 '{
33 model: "claude-haiku-4-5-20251001",
34 max_tokens: 300,
35 messages: [{
36 role: "user",
37 content: ("Go code quick review. ONLY flag CRITICAL:\n1. Error not wrapped (return err without fmt.Errorf)\n2. float64 for money (must int64)\n3. _ ignoring errors\n4. Architecture violation (handler import repo impl)\nDiff:\n" + $diff + "\nOutput: CRITICAL:[file:line issue] or OK")
38 }]
39 }'
40 )" | jq -r '.content[0].text' 2>/dev/null || echo "OK")
41
42if echo "$REVIEW" | grep -q "^CRITICAL:"; then
43 echo ""
44 echo "AI Pre-commit Review — CRITICAL ISSUES FOUND:"
45 echo "$REVIEW"
46 echo ""
47 echo "Fix the issues above before committing."
48 echo "Skip (not recommended): git commit --no-verify"
49 exit 1
50fi
51
52echo "AI Pre-commit: OK"
53exit 0This hook gives the developer feedback before pushing, when fixing is still cheapest — only CRITICAL issues are blocked so as not to disrupt the daily workflow. To install it cleanly, use a pre-commit framework as shown below.
1# Install the hook:
2chmod +x .git/hooks/pre-commit
3
4# Alternative: use the pre-commit framework
5# .pre-commit-config.yaml
6repos:
7 - repo: local
8 hooks:
9 - id: ai-review
10 name: AI Quick Review
11 entry: .git/hooks/pre-commit
12 language: script
13 types: [go]By registering the hook in .pre-commit-config.yaml, the whole team gets the same gate consistently instead of relying on each developer installing the hook manually.
18.3 A Complete GitHub Actions Workflow
After the pre-commit, the next layer is the GitHub Actions pipeline. The workflow below arranges five jobs — from the standard build/test to AI review and failure analysis — with AI used only where it’s appropriate.
1# .github/workflows/ci.yml
2
3name: CI Pipeline with AI Quality Gates
4
5on:
6 push:
7 branches: [main, develop]
8 pull_request:
9 branches: [main, develop]
10 types: [opened, synchronize, ready_for_review]
11
12env:
13 GO_VERSION: '1.22'
14
15jobs:
16 # Job 1: Standard Go (always run, no AI, fast)
17 go-build-test:
18 name: Build & Test
19 runs-on: ubuntu-latest
20 steps:
21 - uses: actions/checkout@v4
22 - uses: actions/setup-go@v5
23 with:
24 go-version: ${{ env.GO_VERSION }}
25 cache: true
26
27 - name: Build
28 run: go build ./...
29
30 - name: Test with Race
31 run: go test -race -count=1 -timeout=5m ./...
32
33 - name: Coverage Gate
34 run: |
35 go test -coverprofile=coverage.out ./...
36 COVERAGE=$(go tool cover -func=coverage.out | \
37 grep "total:" | awk '{print $3}' | tr -d '%')
38 echo "Test coverage: ${COVERAGE}%"
39 if awk "BEGIN {exit ($COVERAGE >= 70) ? 0 : 1}"; then
40 echo "Coverage ${COVERAGE}% >= 70%"
41 else
42 echo "Coverage ${COVERAGE}% < 70% threshold"
43 exit 1
44 fi
45
46 - name: Vet
47 run: go vet ./...
48
49 - name: golangci-lint
50 uses: golangci/golangci-lint-action@v6
51 with:
52 version: latest
53
54 # Job 2: Architecture Enforcement (no AI, custom Go script)
55 architecture-check:
56 name: Architecture Boundary Check
57 runs-on: ubuntu-latest
58 steps:
59 - uses: actions/checkout@v4
60 - uses: actions/setup-go@v5
61 with:
62 go-version: ${{ env.GO_VERSION }}
63
64 - name: Check layer boundaries
65 run: go run ./scripts/check-architecture.go ./...
66
67 # Job 3: AI PR Review (only for non-draft PRs)
68 ai-pr-review:
69 name: Copilot PR Review
70 runs-on: ubuntu-latest
71 if: |
72 github.event_name == 'pull_request' &&
73 !github.event.pull_request.draft
74 permissions:
75 pull-requests: write
76 contents: read
77 steps:
78 - uses: actions/checkout@v4
79 with:
80 fetch-depth: 0
81 - uses: github/copilot-for-pull-requests@v1
82 with:
83 github-token: ${{ secrets.GITHUB_TOKEN }}
84 review-instructions: |
85 Review Go code. Flag as CRITICAL:
86 - Error not wrapped: return err (must fmt.Errorf)
87 - Repository returns error for not-found (must nil, nil)
88 - float64 for monetary values
89 - Architecture violations (wrong layer imports)
90 - Errors ignored with _
91 End with REVIEW_SCORE: X/100
92
93 # Job 4: AI-generated PR description (only for new PRs)
94 generate-pr-description:
95 name: Generate PR Description
96 runs-on: ubuntu-latest
97 if: github.event.action == 'opened'
98 permissions:
99 pull-requests: write
100 contents: read
101 env:
102 ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
103 steps:
104 - uses: actions/checkout@v4
105 with:
106 fetch-depth: 0
107 - uses: actions/setup-node@v4
108 with:
109 node-version: '20'
110 - name: Generate and update PR description
111 uses: actions/github-script@v7
112 with:
113 script: |
114 const { execSync } = require('child_process');
115 const diff = execSync(
116 'git diff origin/main...HEAD -- "*.go" 2>/dev/null | head -300',
117 { encoding: 'utf-8' }
118 );
119
120 if (!diff.trim()) {
121 console.log('No Go changes detected');
122 return;
123 }
124
125 const res = await fetch('https://api.anthropic.com/v1/messages', {
126 method: 'POST',
127 headers: {
128 'x-api-key': process.env.ANTHROPIC_API_KEY,
129 'anthropic-version': '2023-06-01',
130 'content-type': 'application/json',
131 },
132 body: JSON.stringify({
133 model: 'claude-haiku-4-5-20251001',
134 max_tokens: 600,
135 messages: [{
136 role: 'user',
137 content: `Generate a PR description from this Go diff.
138Format:
139## Summary
140[one paragraph on what this PR does]
141
142## Changes
143- [bullet list of key changes]
144
145## Testing
146- [ ] go test -race ./...
147
148Diff:
149${diff}`
150 }]
151 })
152 });
153
154 const data = await res.json();
155 const body = data.content?.[0]?.text || '';
156
157 await github.rest.pulls.update({
158 owner: context.repo.owner,
159 repo: context.repo.repo,
160 pull_number: context.issue.number,
161 body
162 });
163
164 # Job 5: Test failure analysis (only on failure)
165 analyze-test-failure:
166 name: Analyze Test Failure
167 runs-on: ubuntu-latest
168 needs: go-build-test
169 if: failure() && github.event_name == 'pull_request'
170 permissions:
171 pull-requests: write
172 env:
173 ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
174 steps:
175 - uses: actions/checkout@v4
176 - uses: actions/setup-go@v5
177 with:
178 go-version: ${{ env.GO_VERSION }}
179
180 - name: Capture test output
181 run: |
182 go test ./... 2>&1 | head -100 > /tmp/test-output.txt || true
183
184 - name: AI analysis of failure
185 run: |
186 OUTPUT=$(cat /tmp/test-output.txt)
187 ANALYSIS=$(curl -sf -X POST https://api.anthropic.com/v1/messages \
188 -H "x-api-key: ${ANTHROPIC_API_KEY}" \
189 -H "anthropic-version: 2023-06-01" \
190 -H "content-type: application/json" \
191 -d "$(jq -n --arg out "$OUTPUT" '{
192 model: "claude-haiku-4-5-20251001",
193 max_tokens: 300,
194 messages: [{
195 role: "user",
196 content: ("Analyze this Go test failure briefly. Root cause and fix suggestion:\n" + $out)
197 }]
198 }')" | jq -r '.content[0].text' || echo "Analysis failed")
199
200 gh pr comment ${{ github.event.number }} \
201 --body "## AI Test Failure Analysis\n\n${ANALYSIS}"
202 env:
203 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}The design of this pipeline matters: the build/test/architecture jobs run without AI and stay fast, while the AI jobs (review, PR description, failure analysis) are conditioned to run only when relevant — so cost and time stay under control.
18.4 Architecture Enforcement Script
The architecture-check job above calls a Go script with no AI. The script below parses each file’s imports and fails the build if a layer violates the Clean Architecture rules.
1// scripts/check-architecture.go
2// Enforce Clean Architecture layer boundaries
3
4//go:build ignore
5
6package main
7
8import (
9 "fmt"
10 "go/parser"
11 "go/token"
12 "os"
13 "path/filepath"
14 "strings"
15)
16
17// forbiddenImports: layer prefix -> list of forbidden import substrings
18var forbiddenImports = map[string][]string{
19 "internal/delivery": {
20 "internal/repository", // handler must NOT import repo impl
21 "internal/usecase/", // handler imports usecase INTERFACE, not pkg directly
22 },
23 "internal/usecase": {
24 "internal/delivery", // usecase must NOT import handler
25 "github.com/jackc/pgx", // usecase must NOT import DB driver
26 "github.com/redis/go-redis", // usecase must NOT import Redis
27 "github.com/labstack/echo", // usecase must NOT import HTTP framework
28 },
29 "internal/domain": {
30 "github.com/jackc/pgx",
31 "github.com/redis/go-redis",
32 "github.com/labstack/echo",
33 "github.com/confluentinc/confluent-kafka-go",
34 },
35}
36
37func main() {
38 violations := 0
39 fset := token.NewFileSet()
40
41 err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
42 if err != nil || info.IsDir() {
43 return err
44 }
45 if !strings.HasSuffix(path, ".go") {
46 return nil
47 }
48 if strings.HasSuffix(path, "_test.go") {
49 return nil // skip tests
50 }
51
52 // Determine which layer this file is in
53 var currentLayer string
54 for layer := range forbiddenImports {
55 if strings.Contains(path, layer) {
56 currentLayer = layer
57 break
58 }
59 }
60 if currentLayer == "" {
61 return nil
62 }
63
64 f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
65 if err != nil {
66 return nil
67 }
68
69 for _, imp := range f.Imports {
70 impPath := strings.Trim(imp.Path.Value, `"`)
71 for _, forbidden := range forbiddenImports[currentLayer] {
72 if strings.Contains(impPath, forbidden) {
73 fmt.Printf("VIOLATION [%s]: %s\n imports: %s\n\n",
74 currentLayer, path, impPath)
75 violations++
76 }
77 }
78 }
79 return nil
80 })
81
82 if err != nil {
83 fmt.Fprintf(os.Stderr, "walk error: %v\n", err)
84 os.Exit(2)
85 }
86
87 if violations > 0 {
88 fmt.Printf("Total: %d architecture violations\n", violations)
89 os.Exit(1)
90 }
91
92 fmt.Println("Architecture check: PASSED")
93}This script is the highest-value-per-dollar gate: zero AI cost, deterministic, and it catches architecture violations — the kind of bug that’s most expensive if it slips into production. Run it unconditionally on every PR.
18.5 AI-Generated Release Notes
AI is also useful in the post-merge stage, for example composing a changelog. The Go program below gathers commits since the last tag and asks the haiku model to summarize them into clean release notes.
1// cmd/release-notes/main.go
2// Run before each release to generate the changelog
3
4package main
5
6import (
7 "context"
8 "fmt"
9 "os"
10 "os/exec"
11 "strings"
12
13 anthropic "github.com/anthropics/anthropic-sdk-go"
14)
15
16func main() {
17 // Get the commit log from the last tag
18 lastTag, _ := exec.Command("git", "describe", "--tags", "--abbrev=0").Output()
19 tag := strings.TrimSpace(string(lastTag))
20
21 commits, err := exec.Command(
22 "git", "log", "--oneline", "--no-merges",
23 fmt.Sprintf("%s..HEAD", tag),
24 ).Output()
25 if err != nil {
26 fmt.Fprintln(os.Stderr, "No previous tag found, using all commits")
27 commits, _ = exec.Command("git", "log", "--oneline", "--no-merges", "-50").Output()
28 }
29
30 if len(commits) == 0 {
31 fmt.Println("No commits found")
32 return
33 }
34
35 client := anthropic.NewClient()
36
37 msg, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
38 Model: anthropic.F(anthropic.ModelClaudeHaiku4_5),
39 MaxTokens: anthropic.F(int64(800)),
40 Messages: anthropic.F([]anthropic.MessageParam{
41 anthropic.NewUserMessage(anthropic.NewTextBlock(fmt.Sprintf(`
42Generate release notes from the following commit messages for a Go service.
43Clean markdown format:
44
45## What's New
46[new features]
47
48## Bug Fixes
49[bug fixes]
50
51## Internal Changes
52[refactoring, dependencies, etc.]
53
54Commits (from %s to HEAD):
55%s`, tag, string(commits)))),
56 }),
57 })
58 if err != nil {
59 fmt.Fprintf(os.Stderr, "Claude error: %v\n", err)
60 os.Exit(1)
61 }
62
63 fmt.Println(msg.Content[0].Text)
64}This program turns the tedious task of writing a changelog into a single command — even non-descriptive commits still get summarized neatly because the AI groups them by category.
18.6 Cost Estimation for AI in CI/CD
The biggest fear of adopting AI in CI is usually cost. The breakdown below computes a realistic monthly estimate for a 5-developer team and shows that the API calls are not the main cost.
1Monthly cost estimate for a 5-developer team, 3 PRs/dev/week:
2
3Pre-commit hook (haiku):
4 Commits per month: 5 devs × 20 commits = 100
5 Input: ~500 tokens, output: ~100 tokens
6 Cost per commit: $0.0001
7 Monthly: 100 × $0.0001 = $0.01
8
9PR description generation (haiku):
10 PRs per month: 5 × 3 × 4 weeks = 60 PRs
11 Input: ~1000 tokens, output: ~400 tokens
12 Cost per PR: $0.0002
13 Monthly: 60 × $0.0002 = $0.012
14
15Test failure analysis (haiku):
16 Failures per month: ~10 (assuming an 83% PR pass rate)
17 Input: ~500 tokens, output: ~300 tokens
18 Cost per failure: $0.0001
19 Monthly: 10 × $0.0001 = $0.001
20
21Release notes (haiku):
22 Releases per month: 4
23 Cost: 4 × $0.001 = $0.004
24
25Total AI API cost: ~$0.03/month
26GitHub Copilot Business (PR review): $19 × 5 = $95/month
27
28Copilot is the main cost, not the API calls.
29API calls for automation: very affordable.The conclusion from these numbers is reassuring: haiku-based automation only consumes about $0.03/month — the real cost is the Copilot subscription, not the API calls you add yourself.
18.7 Security: Redact Secrets Before AI Review
Sending a diff to an AI API risks leaking a secret. The script below filters common secret patterns from the diff before sending it to the model.
1#!/bin/bash
2# scripts/redact-diff.sh
3# Redact potential secrets from the diff before sending to AI
4
5DIFF="$1"
6
7# Common secret patterns
8echo "$DIFF" | \
9 sed 's/sk-ant-[a-zA-Z0-9_-]*/sk-ant-REDACTED/g' | \
10 sed 's/ghp_[a-zA-Z0-9]*/ghp_REDACTED/g' | \
11 sed 's/AKIA[A-Z0-9]*/AKIAXXXXXXXXXXXXXXXX/g' | \
12 sed 's/password=[^\s]*/password=REDACTED/g' | \
13 sed 's/secret=[^\s]*/secret=REDACTED/g' | \
14 sed 's/DATABASE_URL=postgres:\/\/[^\s]*/DATABASE_URL=postgres:\/\/REDACTED/g'This redaction is an important line of defense: even though an AI provider has a retention policy, preventing secrets from leaving your machine in the first place is far safer. How to use it inside the pipeline is shown below.
1# Use in GitHub Actions:
2- name: Redact secrets from diff
3 run: |
4 git diff origin/main...HEAD -- '*.go' | \
5 bash scripts/redact-diff.sh > /tmp/safe-diff.txt
6
7- name: AI Review on safe diff
8 run: |
9 # Use /tmp/safe-diff.txt instead of the raw diff
10 # ... call the AI API with safe-diff.txtBy placing the redaction step before every AI call, you ensure that what’s sent to the API is always the cleaned version — not the raw diff that might carry credentials.
18.8 Monitoring AI Usage in CI
AI cost needs to be monitored so it doesn’t quietly balloon. The step below logs AI usage metrics to the GitHub Step Summary for cost control.
1# Track AI spending in CI for cost control
2- name: Track AI Usage
3 if: always()
4 run: |
5 # Log basic metrics to the GitHub Step Summary
6 cat >> $GITHUB_STEP_SUMMARY << EOF
7 ## AI Usage This Run
8 - Model: claude-haiku-4-5-20251001
9 - Task: PR description generation
10 - Estimated cost: <$0.001
11 EOF
12
13# Monthly cost report via a scheduled job:
14- name: Monthly AI Cost Report
15 if: github.event_name == 'schedule'
16 run: |
17 # Aggregate from the billing API or manual tracking
18 echo "Review AI tool costs at: anthropic.com/account/usage"Logging the cost estimate per run directly in the workflow summary makes AI spending transparent to the whole team — a billing surprise at the end of the month can be avoided.
18.9 Graduated AI Enforcement
Forcing a full AI gate from day one often triggers resistance. The graduated enforcement strategy below introduces the rules gradually, from a mere warning up to a full score gate.
1A gentler pipeline enforcement strategy for adoption:
2
3PHASE 1 (Month 1): Warning only
4 - The AI review runs but does NOT block merge
5 - The developer sees the output but isn't forced to fix
6 - Collect a baseline: how many issues per PR?
7
8PHASE 2 (Month 2): Enforce CRITICAL only
9 - CRITICAL issues block merge
10 - SUGGESTION remains a warning
11 - Target: zero CRITICAL in merge
12
13PHASE 3 (Month 3+): Full enforcement
14 - CRITICAL blocks merge
15 - SUGGESTION blocks merge if > 5 per PR
16 - Score gate: AI review score < 80 = block
17
18Config for graduated enforcement:
19 .github/ai-enforcement.yml:
20 phase: 2
21 block_on_critical: true
22 block_on_suggestions: false
23 minimum_score: 0 # not enforced yetThis gradual approach keeps adoption humane: the team has time to adjust and build trust in the AI review before the gate starts genuinely blocking merges.
18.10 Tips & Gotchas
The practical lessons below summarize what usually determines the success or failure of AI integration in CI/CD.
Tip 1: Start with just the pre-commit hook — zero GitHub Actions setup, immediate value, and the developer gets feedback before even pushing.
Tip 2: Use the haiku model for CI tasks — 10× cheaper than Sonnet, sufficient for mechanical review in CI. Reserve Sonnet for complex reasoning in developer sessions.
Tip 3: Cache AI results by commit hash — if a PR has no new commits since the last review, skip the AI call to save cost.
Tip 4: The architecture check script (18.4) does NOT need AI — pure static analysis. Run this before the AI steps for a quick catch without cost.
Gotcha 1: The ANTHROPIC_API_KEY in GitHub Secrets must be rotated at least every 6 months. Set up the key with minimal permissions.
Gotcha 2: AI calls add to CI time. Design them as parallel jobs, not sequential. PR description and architecture check can run in parallel.
Gotcha 3: Don’t send the entire codebase to the AI in CI. Only the relevant diff. Sending more = more expensive + slower + possibly exposing unneeded code.
The common thread is clear: use a cheap model for mechanical tasks, run AI jobs in parallel, and limit the input to only the relevant diff — three habits that keep the pipeline fast and cheap.
18.11 Integration with Existing Go Quality Tools
AI is not a replacement for the Go quality tools you already have; it’s an additional layer. The workflow below arranges all the layers — build, test, vet, lint, architecture, then AI — in a logical order.
1# Full pipeline that combines all the tools:
2
3name: Complete Quality Pipeline
4
5on: [pull_request]
6
7jobs:
8 quality:
9 runs-on: ubuntu-latest
10 steps:
11 # Layer 1: Standard Go (fastest, no cost)
12 - name: Build
13 run: go build ./...
14
15 - name: Test
16 run: go test -race ./...
17
18 - name: Vet
19 run: go vet ./...
20
21 # Layer 2: golangci-lint (no AI, great coverage)
22 - uses: golangci/golangci-lint-action@v6
23
24 # Layer 3: Architecture check (no AI, custom rules)
25 - name: Architecture
26 run: go run ./scripts/check-architecture.go ./...
27
28 # Layer 4: AI review (adds judgment, has cost)
29 - name: AI Review
30 if: '!github.event.pull_request.draft'
31 uses: github/copilot-for-pull-requests@v1
32 with:
33 github-token: ${{ secrets.GITHUB_TOKEN }}
34
35# Each layer catches different issues:
36# Build: compilation errors
37# Test: runtime behavior
38# Vet: suspicious constructs
39# golangci-lint: style + common mistakes
40# Architecture: layer boundary violations
41# AI: semantic issues, missing error handling, Go idiomThis layered order is cost-efficient: the free and fast layers (build, test, lint, architecture) filter out the majority of problems first, so the AI only evaluates code that has already passed the cheap gates.
18.12 A Workflow for Database Migration Review
SQL migrations are a high-risk area well suited to a dedicated AI review. The script below asks the AI to flag dangerous migrations (DROP, TRUNCATE, heavy ALTER) before they’re applied.
1#!/bin/bash
2# scripts/review-migration.sh
3# AI review for SQL migration files
4
5MIGRATION_FILE="$1"
6
7if [ -z "$MIGRATION_FILE" ]; then
8 echo "Usage: review-migration.sh <migration-file>"
9 exit 1
10fi
11
12SQL=$(cat "$MIGRATION_FILE")
13
14REVIEW=$(curl -sf -X POST https://api.anthropic.com/v1/messages \
15 -H "x-api-key: ${ANTHROPIC_API_KEY}" \
16 -H "anthropic-version: 2023-06-01" \
17 -H "content-type: application/json" \
18 -d "$(jq -n \
19 --arg sql "$SQL" \
20 '{
21 model: "claude-haiku-4-5-20251001",
22 max_tokens: 400,
23 messages: [{
24 role: "user",
25 content: ("Review SQL migration. Flag:\nBLOCKING: DROP without backup, TRUNCATE, lock-heavy ALTER on large table\nWARNING: Missing index for FK, NOT NULL without default on existing table\nOK: safe migration\n\nMigration:\n" + $sql)
26 }]
27 }'
28 )" | jq -r '.content[0].text')
29
30echo "$REVIEW"
31
32# Block if there are BLOCKING issues
33if echo "$REVIEW" | grep -q "^BLOCKING:"; then
34 exit 1
35fiMigration review is one of the highest-ROI uses of AI in CI: a single migration that locks a large table can cause production downtime, and this gate catches it before merge.
18.13 Slack/Discord Notification with an AI Summary
After a deployment, teams usually want a short, easy-to-read summary. The step below asks the AI to summarize the commits into 2-3 sentences and send them to Slack.
1# Send an AI summary to Slack after deployment
2
3- name: Generate Deployment Summary
4 if: github.ref == 'refs/heads/main' && success()
5 env:
6 ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
7 SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
8 run: |
9 COMMITS=$(git log --oneline --no-merges -10)
10
11 SUMMARY=$(curl -sf -X POST https://api.anthropic.com/v1/messages \
12 -H "x-api-key: ${ANTHROPIC_API_KEY}" \
13 -H "anthropic-version: 2023-06-01" \
14 -H "content-type: application/json" \
15 -d "$(jq -n --arg c "$COMMITS" '{
16 model: "claude-haiku-4-5-20251001",
17 max_tokens: 200,
18 messages: [{
19 role: "user",
20 content: ("Summarize these commits into 2-3 sentences for a Slack deployment notification. Be concise and informative:\n" + $c)
21 }]
22 }')" | jq -r '.content[0].text')
23
24 # Send to Slack
25 curl -X POST "$SLACK_WEBHOOK" \
26 -H "Content-Type: application/json" \
27 -d "$(jq -n \
28 --arg summary "$SUMMARY" \
29 --arg sha "${{ github.sha }}" \
30 '{
31 text: ("*Deployed to Production* :rocket:\n" + $summary + "\nCommit: " + $sha[:8])
32 }'
33 )"A notification like this turns a dry list of commits into a summary even a non-engineer can understand — increasing deployment visibility with no manual effort.
18.14 Metrics Tracking for the AI CI Pipeline
To be able to evaluate the effectiveness of the AI review, its results need to be recorded as metrics. The step below saves the review score and critical status to an artifact for monthly trend analysis.
1# Track the effectiveness of AI in CI with simple metrics
2
3# In GitHub Actions, save to GitHub Variables:
4- name: Track AI Review Effectiveness
5 uses: actions/github-script@v7
6 with:
7 script: |
8 // Get the AI review result from the previous step
9 const aiScore = parseInt(process.env.AI_SCORE || '0');
10 const hasCritical = process.env.HAS_CRITICAL === 'true';
11
12 // Log to the PR comment for tracking
13 const body = [
14 `## AI Quality Metrics`,
15 `- Score: ${aiScore}/100`,
16 `- Critical issues: ${hasCritical ? 'YES' : 'None'}`,
17 `- Timestamp: ${new Date().toISOString()}`,
18 ].join('\n');
19
20 // Store as a workflow artifact for monthly analysis
21 require('fs').writeFileSync(
22 `ai-metrics-${context.payload.number}.json`,
23 JSON.stringify({ pr: context.payload.number, score: aiScore, hasCritical, timestamp: new Date() })
24 );
25
26# Monthly: aggregate the metrics JSON files for trend analysis
27# "Average AI review score trending up = context files improving"These metrics close the feedback loop: a review score that rises month over month is quantitative proof that the team’s context files and code quality are improving.
18.15 Troubleshooting Common CI/AI Issues
AI integration in CI has its own characteristic problems. The guide below maps the most frequent problems along with their practical solutions.
1Problem: The pre-commit hook is too slow (> 30 seconds)
2Solution:
3 1. Use haiku (not sonnet) — 3× faster
4 2. Limit the diff size: head -200 before sending to AI
5 3. Only check CRITICAL rules (3-4 rules, not 10+)
6 4. Cache the result: if the file didn't change, skip
7
8Problem: The AI review score varies for the same code
9Solution:
10 1. A structured prompt with exact rules
11 2. A specific format request ("CRITICAL: or OK only")
12 3. Use temperature=0 if the API supports it
13
14Problem: Annoying false positives
15Solution:
16 1. Add exception rules to the prompt
17 "Exception: test files may use _ for errors"
18 "Exception: main.go may use log.Fatal"
19 2. Update CLAUDE.md for explicit exceptions
20 3. Track what kind of false positives, update the rules
21
22Problem: The AI review doesn't catch issues that slip through
23Solution:
24 1. Add a rule specific to that issue
25 2. Include a code example in the review prompt
26 3. Test the prompt with code that explicitly violates the ruleThe solution pattern is consistent: a structured, specific prompt, limited input, plus a continually updated list of exceptions — a combination that makes AI review stable and trustworthy.
18.16 Summary
AI in CI/CD is the last layer of the quality-gate stack. It’s not a replacement for tests or lint — but an addition that catches patterns static analysis cannot.
Recommended setup per phase:
- Week 1: Pre-commit hook (local, cheap, immediate)
- Week 2: Copilot PR review (if you already have Copilot)
- Week 3: Architecture check script (zero AI cost)
- Month 2: Test failure analysis, PR description generation
The total setup for all of this is 1-2 days, with an ongoing cost of < $1/month for API calls — the value produced is a faster review cycle and human reviewers who can focus on logic, not mechanical issues. Combined with the context files and multi-tool workflow from the previous articles, this completes the AI-driven Go development ecosystem. The next step is to make sure all of this automation is secure: the security and privacy of AI coding tools.