eslint-plugin-slop: Catching AI-Infected Code in CI
The irony writes itself. We used AI to generate code faster, and now we need AI — or at least an ESLint plugin — to tell us when the code smells like AI. Anthony Fu's eslint-plugin-slop landed on npm today at v0.1.2, and it is the most honest name in the JavaScript ecosystem.
Seven rules. Each one targets a fingerprint of AI-generated code that a human reviewer would catch on instinct but CI pipelines miss. I cloned the repo, built it, ran it against deliberately sloppy test files, and measured exactly what catches and what slips through.
The Seven Rules
The plugin ships with two config entries: a universal one that applies everywhere, and a JavaScript-specific one. Every rule is an error by default. No gradual adoption, no "warn" mode — Fu ships with conviction.
| Rule | What it catches | Scope |
|---|---|---|
no-em-dash | Literal U+2014 characters in any source file | Universal |
no-jargon | Inflated vocabulary in comments (utilize, leverage, delve, seamless… 27 words) | JS/TS |
max-comment-length | Comment blocks over 50 words (header blocks exempted) | JS/TS |
no-trivial-functions | Low-use forwarding functions not exported through ESM | JS/TS |
prefer-jsdoc | // comments on exports, autofixed to /** */ | JS/TS |
no-trivial-type-aliases | Type aliases that resolve through same-file chains to unknown or a primitive | JS/TS |
no-chained-type-assertions | Two or more nested assertions (e.g. as unknown as T → as any as U) | JS/TS |
The jargon list is the highlight. Fu compiled 27 words that cluster in AI-generated prose — utilize, leverage, facilitate, streamline, seamless, robust, comprehensive, meticulous, crucial, pivotal, myriad, plethora, paramount, holistic, multifaceted, nuanced, synergy, bolster, encompass, endeavor, aforementioned, commence. Each comes with a suggested replacement in the fix output. Utilize → use. Facilitate → help. Commence → start.
The Git Inspection Mode
This is the feature that makes the plugin usable on existing codebases. Instead of flooding you with 5,000 pre-existing violations on first run, the plugin compares the linted file against git history and only flags changed lines.
Three modes:
uncommitted— compares againstHEAD, catches staged + unstaged + untracked changesrecent-changes— compares againstHEAD~5, catches the last 5 commits of workfull— inspect the entire file, no git filtering
I tested this. A file with legacy jargon in comments and a single new line of AI-generated code produced exactly 2 errors — both on the new line. The pre-existing slop was invisible. When I switched to full mode, all 5 violations appeared. This is the difference between a plugin you can adopt today and a plugin that stays on your wishlist.
Testing It: 13 Errors in 20 Lines
I wrote a small TypeScript file with deliberate AI slop: a 5-line Javadoc-style comment stuffed with jargon, two trivial forwarding functions, two pointless type aliases, and a pair of chained assertions. The plugin found every one:
$ npx eslint src/slop.ts
1:30 error Avoid "robust" in comments. Prefer plainer wording...
1:48 error Avoid "facilitate" in comments.
2:36 error Avoid "comprehensive" in comments.
2:66 error Avoid "leveraging" in comments.
4:7 error Avoid "encompasses" in comments.
4:21 error Avoid "myriad" in comments.
16:1 error This alias adds no structure to its primitive type.
20:18 error This assertion chain discards type evidence.
✖ 13 problems (13 errors, 0 warnings)
13 errors in 20 lines. Every rule fired correctly. The no-trivial-functions rule caught non-exported forwarding functions (loadUser that just calls db.getUser(id)) but correctly skipped exported ones — a deliberate design choice that assumes public API surface is intentional.
I also tested the no-em-dash rule on markdown (the universal rule targets every parser-compatible language). It found em dashes in a comment. It would find them in READMEs, docs, changelogs — anywhere AI rewrites prose.
One Rough Edge
The recent-changes mode defaults to HEAD~5. On a shallow clone or a repo with fewer than 5 commits, git rev-parse --verify HEAD~5 fails and the baseline falls back to an empty string — which means every line is treated as "added" and the rule inspects the entire file. The README documents this behavior ("If the requested history is unavailable, the rules inspect the complete file"), but it's a sharp corner for new projects, which are exactly the ones most likely to have AI-generated code that needs catching.
Workaround: use uncommitted mode on young repos, or set tracebackCommits to a value smaller than your commit count.
The Anti-Slop Ecosystem
Fu's plugin didn't emerge from a vacuum. Three projects laid groundwork:
- dmmulroy/anti-slop — cataloged the recurring low-value patterns that AI generates
- jantimon/eslint-plugin-no-comment-slop — inspired the jargon list and the
prefer-jsdocrule - vibecheck — a broader "ESLint for AI slop" that also supports Python
Fu's contribution is the git-inspection system and the polish. The diff package integration, the per-rule override system, the typed config API — this is a production-grade tool, not a weekend experiment. All 44 tests pass, the build outputs clean ESM with TypeScript declarations, and the bundle is 32 kB.
The timing is not coincidental. Two Lobste.rs posts yesterday — "The load-bearing vocabulary of Claude" and "The Endless Temptation of Claude" — both zero in on the same phenomenon: AI-generated text has a tell, and once you see it you can't unsee it. The ESLint plugin is the codification of that instinct.
Bottom Line
eslint-plugin-slop is the most pragmatic tool in the anti-slop ecosystem today. The git diff mode solves the adoption problem that kills every linter with opinions: nobody wants to fix 10,000 pre-existing violations. If you're using ESLint 10 and your team generates code with AI, add this to your config, set it to uncommitted mode, and watch your CI catch the patterns your reviewers were already grumbling about.
The irony is complete. AI made the mess. Now AI — or at least an ESLint plugin named after the mess — is the fastest way to clean it up.