Continuous integration
The whole CI surface is the exit code: 0 if nothing is over the threshold, 1 if something
is. No reporter to configure, no output format to teach the runner.
GitHub Actions
Section titled “GitHub Actions”name: Complexity
on: [push, pull_request]
jobs: bonsai-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npx bonsai-lint --over 15 .No toolchain setup, no caching worth bothering with, no matrix. npx fetches a ~1 MB binary
and the scan itself is fast enough that it is not the thing you wait for. 1.26 million lines
across three languages takes under a second.
GitLab CI
Section titled “GitLab CI”complexity: image: node:22-alpine script: - npx bonsai-lint --over 15 .Failing on regressions only
Section titled “Failing on regressions only”Most existing codebases have findings on day one. Gating on the absolute number means either a threshold so high it catches nothing, or a red build nobody can fix this sprint.
Record what exists, commit it, and the gate then only fires on things that get worse:
npx bonsai-lint --over 15 --write-baseline .git add .bonsai-lint-baseline.jsonCI runs the same command it always did. A unit already in the baseline passes at its recorded score or below; anything new, or anything that climbed, fails. See baselines for how entries are keyed and what happens when code moves.
Why a broken scan fails the build
Section titled “Why a broken scan fails the build”Exit 1 does not only mean “too complex”. It also means the scan could not be trusted: a
path that could not be read, or no supported files found under the paths given.
That is deliberate. A quality gate that silently checks nothing when it is misconfigured is worse than no gate, because it reports success. If you point the command at a directory that does not exist, you want a red build, not a green one.
Machine-readable output
Section titled “Machine-readable output”For anything that needs to consume results rather than just pass or fail:
npx bonsai-lint --over 15 --format json . > complexity.jsonThe shape is documented in JSON output. Findings are sorted worst-first and the ordering is deterministic, because the report is assembled after the scan rather than streamed as results arrive. Two runs of the same commit are byte-for-byte identical regardless of how many workers ran. A diff between runs is always a real change.