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.

RuleWhat it catchesScope
no-em-dashLiteral U+2014 characters in any source fileUniversal
no-jargonInflated vocabulary in comments (utilize, leverage, delve, seamless… 27 words)JS/TS
max-comment-lengthComment blocks over 50 words (header blocks exempted)JS/TS
no-trivial-functionsLow-use forwarding functions not exported through ESMJS/TS
prefer-jsdoc// comments on exports, autofixed to /** */JS/TS
no-trivial-type-aliasesType aliases that resolve through same-file chains to unknown or a primitiveJS/TS
no-chained-type-assertionsTwo or more nested assertions (e.g. as unknown as Tas 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. Utilizeuse. Facilitatehelp. Commencestart.

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:

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:

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.