Agentic CodingGuide

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:

  1. Type checktsc --noEmit, mypy. Fast, catches the obvious
  2. Lint — ESLint, Ruff, golangci-lint. Fail on warnings in CI
  3. Format checkprettier --check. Reject unformatted code
  4. Unit tests — fast, isolated, must pass before merge
  5. Integration tests — real dependencies (DB, APIs)
  6. E2E tests — critical paths only in CI; full suite on schedule
  7. 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@v3 is 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):

  1. Semgrep — SAST for TypeScript, React, Node.js rule sets
  2. Gitleaks — full git history scan (fetch-depth: 0); catches reverted secrets
  3. Trivy — dependency vulnerability scan, fails on CRITICAL/HIGH
  4. 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 cookieshttpOnly: true, secure: flag, sameSite: set, trustedOrigins
  • CORS — not using origin: '*', credentials: true with cookie auth
  • API middlewarerequireAuth and requirePermission actually wired in
  • Environment validationcreateEnv with Zod schemas, minimum secret length
  • Infrastructure hygiene — lockfile committed, .env in .gitignore
scripts/security-review.ts
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.

On this page