Model or dataset
scanaislop/aislop avatar
scanaislop/aislop

aislop: a deterministic linter for the residue AI coding agents leave behind

Catch and fix the code-quality issues AI coding agents leave behind - dead code, unsafe casts, swallowed errors, duplication, security risks, and more. 50+ deterministic rules across 10 language targets, with CLI, CI, and GitHub Actions. No LLM at runtime. MIT.

625 stars33 forksTypeScriptMIT

At a glance

What is it?
aislop is an MIT-licensed CLI that scores a repository from 0 to 100 against 50+ rules aimed at patterns coding agents produce, with no LLM in the runtime path. The interesting part is not the score. It is the refusal to print one when the repository is mostly a language it cannot read.
Who is it for?
Adopt aislop if your team already runs coding agents and you want a cheap, repeatable gate on the specific patterns they emit, especially as a pre-commit hook or a PR check on changed files. Do not adopt it expecting a general-purpose linter, and do not adopt it for a repository that is mostly Swift, Kotlin or Java: the tool withholds the score there by design, so it gives you nothing to gate on.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem is not broken code, it is plausible code

aislop targets a category of defect that conventional tooling is structurally bad at catching. The README lists the patterns it was built for: narrative comments above self-explanatory code, swallowed exceptions, hidden fallbacks, as any casts, hallucinated imports, duplicated helpers, dead code, todo stubs, oversized functions. The framing sentence in the README is blunt about why this matters: tests pass, lint passes, the code rots anyway. That is the gap. A swallowed exception in a catch block is syntactically valid and passes an ESLint config that was never told to look for it. A duplicated helper generated in two different sessions does not trip any rule in a standard linter because each copy is individually fine. The intended user is a team that has adopted an agent like Claude Code, Cursor, Codex or OpenCode and is now reviewing a volume of machine-authored diffs that no human reads line by line. aislop is not trying to replace the compiler or the test suite. It is trying to make the residue visible before it accumulates.

Deterministic rules, no model in the runtime path

The design decision that separates aislop from most tools in this space is stated in the README as a property, not a marketing line: deterministic, no LLM in the runtime path, same code in, same score out. That matters for a CI gate. A score that varies between runs is not a gate, it is a suggestion. The mechanism is a fixed rule set, described as 50+ rules across 10 language targets (TypeScript, JavaScript, Expo / React Native, Python, Go, Rust, Ruby, PHP, C#, C/C++). Each rule has an id, and the README shows ids in a namespaced form: ai-slop/narrative-comment, ai-slop/trivial-comment, security/hardcoded-secret. The scanner walks files, applies the rules for the detected language, and produces diagnostics that are counted and turned into a 0 to 100 score. The README claims sub-second scans, which is plausible for a static rule pass over a typical change set but is not something I can confirm without running it. Coverage is broader than the rule engine alone: the README notes that some checks use optional system tools, and that bundled Ruff and golangci-lint coverage is available after running aislop-tools once. So the architecture is a core deterministic scanner plus optional external analyzers layered on top.

Getting a first score in one command

The fastest path requires no install. The README gives npx aislop@latest scan as the quick start and says it works on any project. For a permanent setup the same CLI is published to several channels: npm install --save-dev aislop, yarn add --dev aislop, pnpm add -D aislop, bun add -d aislop, npm install -g aislop, brew install scanaislop/tap/aislop, or pipx install aislop. The Python route still needs Node.js on PATH, which the README states explicitly. One detail worth reading twice: package installation does not run dependency lifecycle scripts, and you must run aislop-tools once if you want the bundled Ruff and golangci-lint coverage. The core scanner works without it. Scanning itself has a useful set of scoping flags. aislop scan --changes looks at files changed from HEAD, aislop scan --changes --base origin/main compares against a base branch for pull requests, and aislop scan --staged restricts to staged files. Output formats include --json, --sarif for GitHub code scanning, and --format json. Path filtering is available with --include "src/**" and --exclude "dist,gen". node_modules, .git, dist, build and coverage are excluded by default. Configuration lives in .aislop/config.yml, where exclude takes a list of globs and rules takes a map of rule id to severity.

Severity overrides and inline suppression are the parts you will actually tune

A rule set aimed at AI-generated patterns will produce noise on a codebase that already contains those patterns legitimately. aislop handles this in two ways, and both are visible in the README. The first is a per-rule severity map in .aislop/config.yml. The documented values are error, warning and off. The README is precise about the semantics: off drops matching diagnostics, while error and warning rewrite severity before scoring and reporting. An absent map keeps default behavior. That distinction matters because turning a rule off removes it from the score entirely, whereas downgrading it to warning still affects the number. The second mechanism is inline suppression, with an optional reason after a double dash. The README gives this example: a comment reading aislop-ignore-next-line ai-slop/hidden-fallback -- options is validated upstream placed above a line, and a trailing aislop-ignore-line on a line. There is also aislop-ignore-file. The reason field is the better idea here. A suppression with a written justification is reviewable in a diff; a bare disable comment is not. If your team adopts aislop, the config file and the suppression comments become the two artifacts that determine whether the gate stays useful or gets muted into irrelevance.

The score is withheld when the repository is mostly a language aislop cannot read

This is the most defensible design choice in the project and the one most likely to surprise a first-time user. aislop analyses ten language targets. If a repository is mostly something else, the README names Swift, Kotlin and Java as examples, the tool withholds the score rather than computing one from a handful of incidental files. In JSON mode this surfaces as score: null, scoreable: false, and a coverage breakdown. Most linters in this position would either report nothing or report a misleadingly clean result. Printing a number derived from files the tool never parsed would be worse than printing nothing, because a green badge on an unread codebase is actively misleading. The trade-off is real, though. A polyglot monorepo with a large Java service and a TypeScript frontend gets no aggregate number at all, and the coverage breakdown is the only signal about how much of the repository was actually examined. If your workflow depends on a single repository-level score, that constraint decides the question for you.

Where aislop is the wrong tool

Three cases stand out. First, if you want a general-purpose linter, aislop is not one. It is scoped to a specific pattern family, and the README does not claim to replace ESLint, Ruff or golangci-lint. In fact it can wrap two of them, which tells you the intended relationship is complementary. Second, if your primary language is outside the ten listed, the tool will withhold the score and you will have nothing to gate on. Third, the deterministic rule approach has an inherent failure mode: a rule that matches a pattern by shape will eventually match a legitimate instance of that shape. A hidden fallback is sometimes the correct behavior. A cast to any is sometimes the pragmatic choice at a boundary with untyped data. The severity map and inline suppression exist precisely because the rule set cannot distinguish intent, and the burden of that judgement falls on whoever maintains .aislop/config.yml. Expect to spend real time on that file in the first weeks, and expect the rule ids to change as the project moves through its 0.x releases.

Compared with a conventional linter plus a code review checklist

The obvious alternative is what most teams already have: ESLint or Ruff for style and correctness, plus a human review checklist that says look for swallowed errors and duplicated helpers. The difference in approach is worth being concrete about. A conventional linter is configured around the language's own semantics and around rules the team has accumulated over years. It has no notion of an AI-authored change, no scoring model, and no concept of a pattern family like narrative comments or hallucinated imports. aislop inverts this: the rule set is organized around the failure modes of a specific authoring process, and the output is a single comparable number plus a SARIF or JSON report. What aislop gives up is depth per language. A mature ESLint configuration with typed rules will catch things a cross-language rule engine will not. What it gains is a consistent gate across ten languages and a review artifact that a CI job can fail on. The honest framing is that these are complementary layers, and the README's own decision to bundle Ruff and golangci-lint as optional tools supports that reading.

Maintenance, release cadence and the MIT licence

The release history shows a fast 0.x cadence: v0.15.0 on 2026-08-26, v0.16.0 on 2026-08-31, v0.16.1 on 2026-09-09. Three releases in roughly two weeks. For an adopter that cuts both ways. Fixes arrive quickly, and so do rule changes that can move your score without any change to your code. Pinning a version in package.json and upgrading deliberately is the safer posture than tracking latest through npx, particularly if the score is a hard CI gate. The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is a plain permissive licence and it is compatible with the way most teams would vendor or wrap a CLI. I am not a lawyer and this is not legal advice; if you plan to redistribute a modified aislop, read the LICENSE file in the repository rather than this summary. The README also mentions a hosted badge service at badges.scanaislop.com and a score page at scanaislop.com. Those are network services outside the MIT-licensed CLI, and the README does not describe their terms, so treat the badge as a separate dependency from the scanner.

Editorial conclusion

Adopt aislop if your team already runs coding agents and you want a cheap, repeatable gate on the specific patterns they emit, especially as a pre-commit hook or a PR check on changed files. Do not adopt it expecting a general-purpose linter, and do not adopt it for a repository that is mostly Swift, Kotlin or Java: the tool withholds the score there by design, so it gives you nothing to gate on. Verify first that your primary language is one of the ten listed, then run npx aislop@latest scan --changes --base origin/main on a real branch and read the per-rule output before you wire it into CI.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. scanaislop/aislop on GitHub
Community notes

Community notes