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
One step, always on the latest CLI, nothing to bump:
# .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: actions/setup-node@v4
with:
node-version: 24
- run: npx --yes aislop@latest ci
Prefer the Marketplace Action? It wraps setup-node and runs the same gate. @v1 tracks the latest release and version: latest keeps the CLI current, so there is still nothing to bump.
- uses: actions/checkout@v4
- uses: scanaislop/aislop@v1 # or pin a release, e.g. @v0.13.1, for reproducible builds
with:
version: latest # CLI version; or pin one, e.g. "0.13.1"
GitLab CI
Equivalent shape:
# .gitlab-ci.yml
aislop:
image: node:24
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:24.0
steps:
- checkout
- run: npx --yes aislop@latest ci
workflows:
quality-gate:
jobs:
- aislop
Bitbucket Pipelines
Bitbucket clones shallow by default, so a plain --changes (which diffs against HEAD) sees nothing inside a PR. Fetch the target branch and gate on only the changed files with ci --changes --base:
# bitbucket-pipelines.yml
pipelines:
pull-requests:
"**":
- step:
name: aislop gate
image: node:24
clone:
depth: full # branch diffs need history
script:
- git fetch origin "$BITBUCKET_PR_DESTINATION_BRANCH"
- npx --yes aislop@latest ci --changes --base FETCH_HEAD
--base <ref> works on scan and ci on any provider. Point it at the PR target branch to gate only the diff. ci handles the score gate and exit code, so no JSON parsing or hand-rolled threshold is needed.
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.
--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 (values illustrative):
{
"schemaVersion": "1",
"cliVersion": "<version>",
"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": [ ... ]
}