CI/CD & Automation
The same automated feedback as linters and types — just at a scale that needs a build, a test suite, or a fresh agent context.
The same automated feedback as linters and type checks, just further along the speed axis. CI adds redundancy — an independent run in a clean environment that doesn't trust the agent's local results. The goal is still the same: catch issues as early as possible.
Layers of quality checks
Every check is a feedback signal at a different speed and cost. The goal: catch issues as early as possible.
SPEED LAYER WHAT IT CATCHES
─────────────────────────────────────────────────────────────────
Instant ──► 1. ON EDIT Formatting, type hints,
(PostToolUse hook) lint autofix, obvious errors
Seconds ──► 2. PRE-COMMIT Lint errors, secret detection,
(git hooks) complexity violations, types
Minutes ──► 3. CI PIPELINE Unit tests, integration tests,
(on every PR) build, security scan, SAST
Minutes ──► 4. AGENTIC REVIEW Architecture violations,
(on every PR) missing patterns, logic gaps
Minutes/ ──► 5. AGENTIC QA UI flows, visual regressions,
Hours (pre-merge) network behaviour, edge cases
Ongoing ──► 6. PRODUCTION Monitoring, alerts, canary
deploy metrics
─────────────────────────────────────────────────────────────────ON EDIT (not "on save") because agents call the Edit/Write/MultiEdit tool — Claude Code's PostToolUse hooks fire immediately after. See hooks for the matching setup.
CI pipeline
Baseline CI steps — run the cheapest checks first so the agent gets feedback fast:
- Type check —
tsc --noEmit, mypy. Fast, catches the obvious - Lint — ESLint, Ruff, golangci-lint. Fail on warnings in CI
- Format check —
prettier --check. Reject unformatted code - Unit tests — fast, isolated, must pass before merge
- Integration tests — real dependencies (DB, APIs)
- E2E tests — critical paths only in CI; full suite on schedule
- Build — confirm it actually compiles/bundles
CI-specific practices:
- Fail fast — don't wait 10 minutes to tell the agent its types are wrong
- Cache aggressively — deps, build artifacts, test results
- Parallelise — type check, lint, and tests can run simultaneously
- Pin action versions —
@v3is a moving target; pin to a commit hash
Security review in CI
Security scanning should be automatic. A parallel four-job GitHub Actions workflow on every PR, every push to main, and a weekly cron (catches new CVEs in deps you haven't touched):
- Semgrep — SAST for TypeScript, React, Node.js rule sets
- Gitleaks — full git history scan (
fetch-depth: 0); catches reverted secrets - Trivy — dependency vulnerability scan, fails on CRITICAL/HIGH
- Practices — custom script verifying stack-specific security invariants off-the-shelf tools can't express
on:
pull_request:
branches: [main]
push:
branches: [main]
schedule:
- cron: "0 9 * * 1" # Weekly Monday 9am UTC
workflow_dispatch:The custom "practices" check
Every codebase has security invariants that, if broken, create a vulnerability — and those invariants live in config files and wiring code, not in scanner rule sets. A custom script verifies exactly those:
- Auth cookies —
httpOnly: true,secure:flag,sameSite:set,trustedOrigins - CORS — not using
origin: '*',credentials: truewith cookie auth - API middleware —
requireAuthandrequirePermissionactually wired in - Environment validation —
createEnvwith Zod schemas, minimum secret length - Infrastructure hygiene — lockfile committed,
.envin.gitignore
interface CheckResult {
name: string;
category: string;
passed: boolean;
description: string;
}
function checkAuthSecurity(): CheckResult[] {
const authFile = readFileSync("packages/auth/src/index.ts", "utf-8");
return [
{
category: "Auth",
name: "httpOnly cookies",
passed: authFile.includes("httpOnly: true"),
description: "httpOnly prevents JavaScript access to auth cookies (XSS protection).",
},
{
category: "Auth",
name: "SameSite cookie attribute",
passed: authFile.includes("sameSite:"),
description: "SameSite attribute prevents CSRF attacks.",
},
{
category: "Auth",
name: "Trusted origins validated",
passed: authFile.includes("trustedOrigins"),
description: "trustedOrigins prevents cross-origin auth abuse.",
},
];
}Write one check per invariant, point it at the specific file. The script fails the build the moment someone (human or agent) breaks the contract.
Security scanning in CI is cheap. A security incident is not.