Skip to main content
New aislop v0.10.2: safer GitHub Action pins, reproducible init workflows, and cleaner rule docs. Read the changelog →

CI / CD.

aislop ci is the quality gate: same scan as local, exits non-zero when the score drops below your threshold or any error is present. Wire it wherever your CI runs.

Fastest path — let init write it

npx aislop init will ask "Add a GitHub Actions workflow?" — say yes and it drops a ready-to-run .github/workflows/aislop.yml. Commit it alongside .aislop/config.yml. That's the whole setup.

.github/workflows/aislop.yml is the GitHub Actions workflow file. You can rename it, but it must stay under .github/workflows/. .aislop/config.yml is the policy file: thresholds, engines, scoring, and telemetry live there.

$ npx aislop init

GitHub Actions

If you'd rather hand-write it, use the Marketplace Action. It wraps setup-node and runs the same aislop ci gate:

# .github/workflows/aislop.yml
name: aislop

on:
  pull_request:
  push:
    branches: [main]

jobs:
  quality-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: scanaislop/aislop@v0.10.2
        with:
          version: latest

There are two versions here. uses: scanaislop/aislop@v0.10.2 pins the GitHub Action wrapper to a real Git tag. version: latest tells the wrapper to run the latest npm CLI. GitHub does not resolve uses: ...@latest unless the repo maintains a branch or tag named latest.

For deterministic CI, pin both layers:

- uses: actions/checkout@v4

- uses: scanaislop/aislop@v0.10.2
  with:
    version: "0.10.2"

If you do not want the Marketplace Action, keep the workflow self-contained:

- uses: actions/checkout@v4
- uses: actions/setup-node@v4
  with:
    node-version: 20
- run: npx --yes aislop@latest ci

GitLab CI

Equivalent shape:

# .gitlab-ci.yml
aislop:
  image: node:20
  script:
    - npx --yes aislop@latest ci
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

CircleCI

# .circleci/config.yml
version: 2.1

jobs:
  aislop:
    docker:
      - image: cimg/node:20.0
    steps:
      - checkout
      - run: npx --yes aislop@latest ci

workflows:
  quality-gate:
    jobs:
      - aislop

Pre-commit hook

Run aislop on only staged files before a commit lands — catches slop before CI even sees it. Any pre-commit tool (Husky, lefthook, pre-commit.com) works.

# Husky — .husky/pre-commit
npx aislop scan --staged

--staged only scans files staged for commit, so the hook stays fast. Use aislop fix --staged in a pre-commit flow to auto-fix staged files, then re-add them.

Branch protection

Once aislop runs on every PR, make it required. In GitHub: Settings → Branches → Branch protection rules → Require status checks to pass before merging, then tick the aislop job. From that point, a PR that drops the score below ci.failBelow can't be merged without an explicit override.

This is where the quality gate becomes real. A CI check that only lints is advisory; a required status check is policy.

Exit codes

0 — score ≥ ci.failBelow and no error-severity diagnostics. CI passes.
1 — score below threshold, or at least one error-severity diagnostic. CI fails.
non-zero — other runtime failures (bad config, missing Node, etc). Check stderr.

Reading the JSON output

aislop ci emits JSON on stdout. Shape:

{
  "schemaVersion": "1",
  "cliVersion": "0.10.2",
  "score": 87,
  "label": "Healthy",
  "engines": {
    "format":       { "issues": 0, "skipped": false, "elapsed": 406 },
    "lint":         { "issues": 0, "skipped": false, "elapsed": 378 },
    "code-quality": { "issues": 1, "skipped": false, "elapsed": 812 },
    "ai-slop":      { "issues": 2, "skipped": false, "elapsed": 455 },
    "security":    { "issues": 0, "skipped": false, "elapsed": 1103 }
  },
  "diagnostics": [ ... ]
}