CI/CD for Design: Catching AI Slop Before It Ships
Integrate design quality checks into your CI/CD pipeline. Catch AI-generated visual defaults in pull requests before they reach production.
You lint your code. You type-check your code. You test your code. But you ship your design unchecked. Every pull request could introduce AI-generated visual defaults and you wouldn't know until someone looks at the page and says "this looks generic." Sailop's CI/CD integration changes that.
The Gap in Your Pipeline
Modern frontend pipelines are thorough about code quality:
- ESLint catches code patterns and anti-patterns
- TypeScript catches type errors
- Prettier enforces formatting
- Jest/Vitest catches functional regressions
But none of these tools care about what the output looks like. A component can pass every lint rule, every type check, every test, and still produce a visually generic page with blue-500 buttons and Inter font.
This is the gap. Design quality has been a human-review-only concern. And as AI generates more and more frontend code, human reviewers can't catch every transition-all duration-300 ease-in-out that slips in. First, understand what AI slop is and why it matters -- then automate the detection.
sailop check: The Design Linter
The sailop check command works like a linter but for visual patterns:
# Check files with a maximum score threshold
sailop check ./src --max-score 50
# Exit code 0 if all files are below the threshold
# Exit code 1 if any file exceeds the thresholdThis is the building block for CI integration. Set a maximum DNA score, and the command fails if any file exceeds it.
# Strict: nothing above 40 (Grade B or better)
sailop check ./src --max-score 40
# Moderate: nothing above 60 (Grade C or better)
sailop check ./src --max-score 60
# Lenient: nothing above 80 (catch only the worst offenders)
sailop check ./src --max-score 80GitHub Actions Integration
Here's a complete GitHub Actions workflow that checks design quality on every pull request:
# .github/workflows/design-check.yml
name: Design Quality Check
on:
pull_request:
paths:
- 'src/**/*.tsx'
- 'src/**/*.css'
- 'src/**/*.html'
jobs:
sailop-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Sailop
run: npm install -g sailop
- name: Run DNA scan
run: sailop ci ./src --fail-above 60 --format json > sailop-report.json
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: sailop-report
path: sailop-report.json
- name: Comment on PR
if: failure()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('sailop-report.json', 'utf8'));
const body = `## Sailop Design Check Failed
DNA Score: **${report.score}/100** (Grade ${report.grade})
Threshold: 60/100
| Dimension | Score |
|-----------|-------|
| Color | ${report.dimensions.color} |
| Typography | ${report.dimensions.typography} |
| Layout | ${report.dimensions.layout} |
| Animation | ${report.dimensions.animation} |
| Components | ${report.dimensions.components} |
| Structure | ${report.dimensions.structure} |
| Spacing | ${report.dimensions.spacing} |
Run \`sailop fix ./src --apply\` to auto-fix detected patterns.`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});This workflow:
- Triggers only on PRs that modify frontend files
- Runs the Sailop CI scanner
- Fails the check if the DNA score exceeds 60
- Comments on the PR with a detailed breakdown
Pre-Commit Hook
For faster feedback, add a pre-commit hook that catches AI slop before it even reaches the PR:
# Install the pre-commit hook
sailop hook install
# Or manually add to .husky/pre-commit:
sailop check ./src --max-score 50 --staged-onlyThe --staged-only flag checks only files that are about to be committed, keeping the hook fast.
// package.json
{
"scripts": {
"lint": "eslint src/",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"design-check": "sailop check ./src --max-score 50"
},
"lint-staged": {
"*.{tsx,css,html}": ["sailop check --max-score 50"]
}
}sailop ci: Structured Output
The sailop ci command is designed specifically for automation. It outputs structured JSON that other tools can consume:
sailop ci ./src --fail-above 60 --format json{
"score": 72,
"grade": "D",
"pass": false,
"threshold": 60,
"dimensions": {
"color": 81,
"typography": 68,
"layout": 75,
"animation": 90,
"components": 65,
"structure": 58,
"spacing": 67
},
"files": [
{
"path": "src/app/page.tsx",
"score": 72,
"findings": [
{ "rule": "color-blue-range", "severity": "high", "message": "Primary color in AI blue band (hue 217)" },
{ "rule": "animation-transition-all", "severity": "high", "message": "transition-all detected (use specific properties)" }
]
}
],
"timestamp": "2026-02-12T14:30:00Z"
}Gradual Adoption
You don't need to enforce a strict score on day one. Here's a gradual adoption strategy:
Week 1-2: Observe
# Run scan without failing, just collect data
sailop ci ./src --format json > baseline.jsonWeek 3-4: Warn
# Fail only on Grade F (score > 80)
sailop check ./src --max-score 80Month 2: Moderate
# Fail on Grade D or worse (score > 60)
sailop check ./src --max-score 60Month 3+: Strict
# Fail on anything below Grade B (score > 40)
sailop check ./src --max-score 40This lets the team gradually improve scores without blocking all work on day one.
Dimension-Specific Checks
Not every team cares about every dimension. You can run checks on specific dimensions:
# Only check animation patterns (the most common AI tells)
sailop check ./src --dimension animation --max-score 40
# Only check color and typography
sailop check ./src --dimension color,typography --max-score 50
# Ignore structure dimension
sailop check ./src --skip-dimension structure --max-score 50Integration With Existing Tools
Sailop's CI output works with:
- GitHub Actions: Native integration via exit codes and JSON output
- GitLab CI: Same exit code behavior, pipe JSON to artifacts
- Bitbucket Pipelines: Use the CLI directly in your pipeline scripts
- Jenkins: Parse JSON output in post-build steps
- Vercel: Add to build command in vercel.json
// vercel.json
{
"buildCommand": "sailop check ./src --max-score 60 && next build"
}What It Catches
In practice, here are the most common findings from CI scans:
- transition-all duration-300 (Animation, 89% of flagged files)
- blue/indigo primary color (Color, 73% of flagged files)
- Inter/system-ui only (Typography, 68% of flagged files)
- rounded-lg everywhere (Components, 61% of flagged files)
- 4px-grid-only spacing (Spacing, 57% of flagged files)
These are the patterns that AI-generated code introduces most frequently. For the full catalog, see our definitive list of 90+ AI design patterns to avoid. Catching them in CI means they never reach production.
The Complete Stack
ESLint catches bad code patterns. TypeScript catches type bugs. Tests catch broken behavior. Sailop catches visual homogeneity. Together, they cover the full quality spectrum. For a detailed comparison of Sailop and ESLint, read Sailop vs ESLint: why design needs its own linter. For the complete anti-slop workflow, see our complete guide to anti-AI design.
npm install -g sailop
sailop hook installSet it up once, catch AI slop forever. Start at sailop.com.
Try Sailop
Scan your frontend for AI patterns. Generate a unique design system. Ship code that looks intentional.