SlopScore
00 crowd

stopslop

Like Ruff, but for AI slop. A fast, deterministic linter that catches AI-generated code mistakes in TypeScript, Python, Go, and Rust. No LLM at scan time.
Open repo on GitHubgithub.com/mgiovani/stopslop
Rust · ★ 1 · 0 forks · MIT · paperwork by the Cap'mmostly ai (inferred)light human (inferred)works-on-my-machine (inferred)devtools
listed 1 hour ago by mgiovani · last checked 1 hour ago
The owner didn't write this. This repo never submitted itself. The Cap'm found it on a truffle trawl and wrote its paperwork from what GitHub already shows. Picked by hand by the Cap'm on 2026-09-13: Like Ruff, but for AI slop. A fast, deterministic linter that catches AI-generated code mistakes in TypeScript; its own README says "It never scores a file as "written by AI" and never needs a model to say so". 1 stars; MIT license. The owner did not submit this. Votes count; awards don't until the owner claims it.

I'm not calling your project slop! Geeze, it's a joke... Do you own this repo?

Log in with GitHub as mgiovani. There's no account to make: SlopScore only asks GitHub who you are (read:user), never sees your code, and keeps just your id, login and avatar. Then you can:

  • Keep it, on your terms. Commit your own slopscore.md (spec) and press Refresh. Your paperwork replaces the Cap'm's, and you can submit it for Slop of the Day.
  • Take it down. One click on Remove. It stays gone; the trawl never brings it back.

Log in with GitHub

Can't log in as the owner? Request a takedown. No login needed, and a trawled listing comes down right away.

GitHub says
Like Ruff, but for AI slop. A fast, deterministic linter that catches AI-generated code mistakes in TypeScript, Python, Go, and Rust. No LLM at scan time.
topics
ai-generated-codeai-slopai-slop-detectionai-slop-detectorai-slop-fixerai-slop-lintercicode-qualitydeveloper-toolslinterrustsarifstatic-analysistree-sitter
created
2026-07-12 · pushed 4 days ago · 123 commits · 2 contributors
release
v0.5.1 · 2026-08-14
languages
Rust 99%Python 0%Shell 0%
paperwork
licensereadme 42% health
dependencies
✓ 209 deps, none with known advisories · OSV.dev, checked 1 hour ago

The Cap'm's log

The Cap'm wrote this paperwork, not the owner. This repo never submitted itself to SlopScore. The Cap'm picked it by hand: Like Ruff, but for AI slop. A fast, deterministic linter that catches AI-generated code mistakes in TypeScript; its own README says "It never scores a file as "written by AI" and never needs a model to say so". It carries the MIT license. The disclosures above are his best guess from what GitHub shows.

Is this yours? Commit a real slopscore.md and press Refresh to replace this, or remove the listing in one click. There's no account to make: you log in with GitHub.

README — the repo's own words, folded up so the grading fits on one screen

stopslop: Like Ruff, but for AI slop. Catch the junk AI leaves in your code.

stopslop

Catch the junk AI leaves in your code.

CI License: MIT Crates.io

stopslop demo

Your linter can't see // ... rest of code unchanged. ESLint, Ruff, and Clippy throw away comment and string content before analysis: exactly where AI coding artifacts live. stopslop reads what they discard: leaked chat preambles, elision comments that silently deleted code, stray markdown fences, placeholder credentials, and package imports that don't resolve to anything you declared. It reads your prose too: Markdown, MDX, plain text, reST, and HTML get the same deterministic treatment. One static binary, no LLM at scan time: same input, same output, every run.

  • One fast static binary, zero config to get started.
  • Deterministic: no LLM calls, no API calls, no network access at scan time.
  • Built for CI: exit codes, SARIF, JSON, and inline suppressions.

Why your existing linter misses this

ESLint, Ruff, and Clippy parse comments and strings as trivia their default rule sets don't inspect, which is exactly where copy-pasted chat output and truncated edits land. A few examples:

Artifact ESLint / Ruff / Clippy stopslop
// ... rest of code unchanged Not linted (comment content is ignored by default rules) SLOP001
Leaked chat preamble ("Certainly! Here's...") Not linted (same reason) SLOP002
x as unknown as T type-escape chain No stock rule (as unknown alone is valid, idiomatic TS) SLOP007
YOUR_API_KEY, sk-...-shaped secret Not linted (string literal content is ignored by default rules) SLOP009

stopslop is a deterministic linter for TypeScript, Python, Go, and Rust. Every rule is a tree-sitter AST match or a regex over extracted comments/strings: same input, same output, every time. This is a quality gate that also names AI tells: it flags patterns that are junk regardless of who (or what) produced them, and patterns that are known giveaways of machine-generated text or code, so you can rewrite either. It never scores a file as "written by AI" and never needs a model to say so.

Install

cargo install stopslop

Once a day, an outdated install prints a one-line update notice to stderr (never in CI, never for --format json|sarif|markdown, never when stderr is not a terminal). Set STOPSLOP_NO_UPDATE_CHECK=1 (or NO_UPDATE_NOTIFIER=1) to turn it off.

Alternatives:

# latest main, for a merged-but-unreleased fix
cargo install --git https://github.com/mgiovani/stopslop

# local checkout, for hacking on stopslop itself
git clone https://github.com/mgiovani/stopslop
cd stopslop
cargo install --path .

Usage

stopslop                          # lint the current directory
stopslop src/ lib/                 # lint specific paths
stopslop --format json .           # machine-readable output
stopslop --stats .                 # files/lines scanned, wall time, throughput (stderr)
stopslop -j 1 .                    # single worker thread (perf work; 0 = automatic)
stopslop --select SLOP001          # run only the elision rule
stopslop --select rhetoric         # run one rule group (see "Rule groups" below)
stopslop --select ALL              # every rule (SLOP010 still needs --check-imports)
stopslop --ignore SLOP008          # run everything except stub detection
stopslop --select artifact --extend-select SLOP033  # add a rule on top of a narrower select
stopslop --list-rules              # print every rule with its group, tier, and default
stopslop --check-imports .         # also run SLOP010 (unresolved import) — opt-in
stopslop --config path.toml        # use a specific config file instead of the discovered one
stopslop --no-config               # ignore any project or user-level stopslop.toml, CLI flags only
stopslop --write-baseline .        # record today's findings (see "Baseline" below)
stopslop --baseline .              # report only findings that aren't in the baseline
stopslop --staged                  # lint what is about to be committed (index content, not disk)
stopslop --changed                 # staged + unstaged changes against HEAD
stopslop --since origin/main       # files changed on this branch, for PR checks

Example output:

stopslop findings across Python and TypeScript files

--format json emits a flat array of findings; --format sarif emits a SARIF 2.1.0 document for GitHub code scanning and similar tools; --format markdown emits the findings grouped under one heading per tier, for pasting into a PR comment or a report. --stats prints a files/lines/wall-time/throughput summary to stderr in text and markdown modes; with --format json the output becomes {"findings": [...], "stats": {...}}, and with --format sarif the same object lands in runs[0].properties.stats. Wall time runs from startup through the walk, so it lines up with an external time. "skipped" counts files the walk reached but could not lint (unsupported extension or unreadable); paths dropped by .gitignore or exclude are never walked and are not counted.

stopslop --format json output

Rule groups

SLOP0NN numbers are chronological, not thematic, so a numeric prefix can't express "just the rhetoric rules". Named groups can. They work anywhere a rule code or prefix does, including --select, --ignore, and the select/ignore keys in stopslop.toml:

Group What it covers
artifact Mechanical leftovers from a generation session: chat turns, tool tokens, unfilled slots
structure Structural code smells: swallowed errors, escaped types, stubs, speculative abstraction
stdlib Code that rebuilds something the standard library or the platform already provides
rhetoric Formulaic rhetorical shapes: clichés, staged reveals, manufactured significance
verbosity Words that cost the reader something and return nothing: hedging, filler, padding
sourcing Claims with no checkable source behind them
format Typographic and Markdown affectations
stopslop --select artifact,structure   # the mechanical, high-confidence rules only
stopslop --select SLOP --ignore verbosity  # everything except the density rules

Every rule belongs to exactly one group; a test enforces that the table stays exhaustive, so a new rule can't quietly escape group selection. --list-rules prints the full mapping.

ALL is a reserved selector, not a group: --select ALL (or select = ["ALL"] in config) runs every registered rule plus any [[custom-rule]] entries from your config. SLOP010 is the one exception: it stays off until --check-imports is passed.

Baseline

Turning stopslop on for an existing codebase usually surfaces findings nobody plans to fix today. A baseline grandfathers them so CI only fails on findings that are new:

stopslop --write-baseline .   # writes .stopslop-baseline.json, exits 0
stopslop --baseline .         # later runs report only what isn't in it

Use --baseline=path.json / --write-baseline=path.json for a different file (the = is required, so a bare --baseline doesn't swallow your scan path), or set baseline = ".stopslop-baseline.json" in stopslop.toml.

Findings are matched by a fingerprint of code + path + message with digits normalized out, not by line number, so editing above a finding doesn't resurrect it and a density count drifting by one doesn't either. Paths are normalized as well, with a leading ./ stripped, so a baseline written from git ls-files (foo.md) still matches a stopslop . run (./foo.md). The file stores a count per fingerprint: if a file has three accepted findings from one rule, it absorbs exactly three, and a fourth is reported. Fix one and the budget shrinks with it. The count ratchets down on its own; raising it takes a deliberate --write-baseline.

Commit the baseline file so CI and local runs agree.

Git-aware selection

--staged, --changed, and --since REF (mutually exclusive) replace the walk with a git-selected file list, so linting scales with the size of a diff instead of the whole tree. Positional paths, if given, act as git pathspecs (stopslop --staged src/ lints only staged files under src).

  • --staged reads each file's staged content (git show :./path), so a partially staged file is checked as it will be committed, not as it sits on disk.
  • --changed includes both staged and unstaged changes against HEAD; untracked files are not included.
  • --since REF diffs against the merge base of REF and HEAD (git 2.30+), so REF advancing after the branch forked doesn't pull in its changes. Built for stopslop --since origin/main on a PR.
  • An empty selection exits 0. All three compose with --baseline, exclude, and [per-file-ignores] exactly like a normal scan.

Pre-commit hook: stopslop --staged.

Rules

Code Group Name Tier Langs NL Description
SLOP001 artifact Elision / "rest unchanged" comment A, on TS, TSX, Python, Go, Rust en, pt-BR A comment like // ... rest unchanged may mark code an AI dropped while truncating an edit
SLOP002 artifact Chat preamble leaked into code A, on TS, TSX, Python, Go, Rust en, pt-BR Chat-assistant preamble ("Certainly! Here's the updated...") pasted straight into a source comment
SLOP003 artifact Stray markdown code fence in source A, on TS, TSX, Python, Go, Rust en, pt-BR A bare ``` fence line left in source, usually from a whole file pasted out of a chat reply
SLOP004 artifact AI attribution / chat-share artifact A, on TS, TSX, Python, Go, Rust en, pt-BR "Generated by ChatGPT", a claude.ai/share link, or other chat-export junk in a comment
SLOP005 structure Empty / log-only catch A, on TS, TSX, Go, Rust en, pt-BR A catch/error branch that swallows the error with an empty body or just a log call
SLOP006 structure Broad / swallowing except A, on Python en, pt-BR A bare or overly broad except: that swallows the exception instead of handling it
SLOP007 structure Type-escape (as any/as unknown/@ts-ignore) A, on TS, TSX en, pt-BR as any, an x as unknown as T chain that fully escapes the type checker, or @ts-ignore/@ts-nocheck
SLOP008 structure Stub-only / unimplemented body A, on TS, TSX, Python, Go, Rust en, pt-BR A function whose entire body is pass/.../throw new Error("not implemented")/todo!()/empty
SLOP009 structure Placeholder / sample credential value A, on TS, TSX, Python, Go, Rust, HTML en, pt-BR A hardcoded YOUR_API_KEY, example.com, sk-...-shaped secret, or other sample value; in HTML attributes also a placeholder-image host (via.placeholder.com, placehold.co) or an alt that is just image
SLOP010 structure Unresolved package import B, off TS, TSX, Python, Go, Rust en, pt-BR An imported package that isn't declared in the project's manifest or stdlib (opt-in, --check-imports)
SLOP011 artifact Assistant-response residue in prose A, on Markdown, MDX, Text, reST, HTML en, pt-BR A leftover chat-turn phrase (self-ID disclaimer, refusal boilerplate, a line-initial Certainly! opener, a trailing let me know if you have closer, reasoning-chain scaffolding like let's think about this, a mid-sentence step 1: that isn't heading a section or list item, or a paragraph-initial acknowledgment loop like To answer your question, ...) left unedited in prose
SLOP012 artifact LLM tool / citation artifact tokens A, on Markdown, MDX, Text, reST, HTML en, pt-BR A leftover search/citation-tool token (turn0search0, :contentReference[oaicite:1], a 【12†L3】 marker, utm_source=chatgpt.com) left in text
SLOP013 artifact Unfilled template placeholder text A, on Markdown, MDX, Text, reST, HTML en, pt-BR An unfilled placeholder ([Your Name], INSERT_SOURCE_URL_30, a date: 2025-XX-XX stub) left in place of real content
SLOP014 rhetoric Formulaic cliché phrase B, on Markdown, MDX, Text, reST, HTML en A stock marketing/narrative cliché (unlock the power of, in today's fast-paced world, a testament to)
SLOP015 verbosity Hedging & filler-phrase density B, on Markdown, MDX, Text, reST, HTML en, pt-BR A document-wide density of hedging/filler phrases (it's worth noting that, in conclusion, first and foremost); an adjacent hedge stack like might potentially fires on its own, without waiting for the density threshold
SLOP016 verbosity Overused-vocabulary density B, on Markdown, MDX, Text, reST, HTML en A document-wide density of overused vocabulary (delve, tapestry, robust, leverage) across enough distinct terms to read as filler
SLOP017 rhetoric Rhetorical parallelism / false-depth scaffolding density B, on Markdown, MDX, Text, reST, HTML en, pt-BR A document-wide density of three-item rhetorical lists and not only X but also Y phrasing. Trailing , underscoring its... participles count toward the same threshold. Longer enumerations and lists of proper nouns are not counted
SLOP018 format Mid-prose em/en dash B, on Markdown, MDX, Text, reST, HTML en, pt-BR A mid-sentence em dash (), en dash (), or spaced ASCII -- that should be rewritten out of the sentence (numeric ranges like 2020–2024, and an attribution dash opening a block or blockquote like — Oscar Wilde, are exempt)
SLOP019 format Boldface & bold-lead-in list overuse B, on Markdown, MDX, HTML en, pt-BR Boldface overuse in body prose, or 3+ consecutive - **Term**: ... bold-lead-in list items
SLOP020 format Typographic (smart) quotes in source B, on Markdown, MDX, Text, reST, HTML en, pt-BR Curly quotes/apostrophes in source where straight ASCII quotes are expected
SLOP021 format Heading & marker formatting affectations B, on Markdown, MDX, HTML en, pt-BR Emoji or a decorative technical symbol used as a heading/list marker (counted and reported separately), headings written in Title Case against an otherwise sentence-case document, or headings stacked over two-sentence sections
SLOP022 rhetoric Formulaic opener / rhetorical setup B, on Markdown, MDX, Text, reST, HTML en, pt-BR A throat-clearing or faux-insight opener (Here's the thing, What nobody tells you, Plot twist:), or a self-answered Question? Answer. pair opening a line
SLOP023 rhetoric Binary contrast / negative listing B, on Markdown, MDX, Text, reST, HTML en, pt-BR The It's not X. It's Y. / The question isn't X, it's Y shape, or a Not a X. Not a Y. fragment run
SLOP024 rhetoric Importance puffery / fake-strong verb B, on Markdown, MDX, Text, reST, HTML en, pt-BR An inflated significance claim (marks a pivotal moment, solidifies its position), a serves as a centralized hub-style linking verb where plain is reads better, or a faux-scale range (from the singularity of the Big Bang to the enigmatic dance of dark matter) standing in for an actual magnitude
SLOP025 sourcing Unsourced weasel attribution B, on Markdown, MDX, Text, reST, HTML en, pt-BR Anonymous authority (experts agree, studies show) with nothing citing it anywhere on the line, whether a link or a footnote. Also flags notability by name-dropping three-plus outlets (cited in TechCrunch, Forbes, and Wired) with no per-citation context
SLOP026 rhetoric Dramatic colon reveal B, on Markdown, MDX, Text, reST, HTML en, pt-BR A short noun phrase, a colon, then a lowercase dramatic reveal (The best part: it learns)
SLOP027 verbosity Empty filler phrase & adverb density B, on Markdown, MDX, Text, reST, HTML en, pt-BR A document-wide density of empty phrases (when it comes to, at its core) and filler adverbs (simply, actually)
SLOP028 verbosity Weak verb phrase / vague quantifier B, on Markdown, MDX, Text, reST, HTML en, pt-BR A document-wide density of nominalizations (made a decision, has the ability to) and vague quantifiers used where a number belongs (significantly improves)
SLOP029 rhetoric Summary-recap ending / fake-profound kicker B, on Markdown, MDX, Text, reST, HTML en, pt-BR A closing block that restates the piece (In conclusion, Overall) or lands a mic-drop line (It's already here.)
SLOP030 rhetoric Dramatic fragmentation / robotic rhythm B, on Markdown, MDX, Text, reST, HTML en, pt-BR Stacked one-clause fragments (That's it. That's the whole thing.), consecutive And-initial sentences, or paragraph-wide repeated sentence shapes
SLOP031 rhetoric Promotional / advertisement language B, on Markdown, MDX, Text, reST, HTML en, pt-BR Brochure register in technical prose (boasts a, industry-leading, a hidden gem) at document-wide density
SLOP032 verbosity Hyphenated-compound overuse B, on Markdown, MDX, Text, reST, HTML en Stacked hyphenated modifiers used as filler (end-to-end, data-driven, battle-tested) at document-wide density
SLOP033 verbosity Overlong sentence B, on Markdown, MDX, Text, reST, HTML en, pt-BR A sentence over 50 words, reported with its actual word count (URLs count as one word)
SLOP034 verbosity Synonym rotation across a closed concept set B, on Markdown, MDX, Text, reST, HTML en, pt-BR One concept named two ways within one section's running prose (check and verify, config and settings) where technical writing should fix one term. Bullet lists and tables are excluded, so a catalog of differently-named things doesn't count as rotation
SLOP035 rhetoric Outline-shaped filler section B, on Markdown, MDX, Text, reST, HTML en, pt-BR A Challenges and Future Prospects-style section heading, or despite these challenges boilerplate, standing in for specifics
SLOP036 rhetoric Diff-anchored documentation B, on Markdown, MDX, Text, reST, HTML en, pt-BR Docs narrating a change (was added to replace, no longer requires) instead of describing current behavior; changelogs and migration guides are exempt
SLOP037 stdlib Reinvented stdlib / native platform feature B, on TS, TSX, Python, Go, Rust en, pt-BR Hand-rolled code where a standard-library or platform primitive exists (JSON.parse(JSON.stringify(x)), for i in range(len(xs)), ioutil.ReadFile)
SLOP038 stdlib Dependency with a stdlib equivalent B, on TS, TSX en, pt-BR An import of a package the platform already covers (moment, uuid, node-fetch, left-pad)
SLOP039 structure Pass-through wrapper function B, on TS, TSX, Python, Go, Rust en, pt-BR A function whose whole body forwards its own parameters, unchanged, to another function
SLOP040 structure Single-implementation interface / abstract B, on TS, TSX, Python en, pt-BR An interface or abstract class with exactly one implementor in the same file: abstraction with no second user
SLOP041 verbosity Mechanical uniformity (templated prose) B, on Markdown, MDX, Text, reST, HTML en, pt-BR A document of 200+ words where at least 2 of 3 document-level signals trip together: flat sentence-length burstiness, low type-token vocabulary ratio, and repeated word-trigrams
SLOP042 verbosity Comment that restates the code B, on TS, TSX, Python, Go, Rust en, pt-BR A plain comment of 2 to 12 words whose content words all already appear in the one statement it sits on, or only name the construct that statement is (// increment the counter above counter += 1), so it adds nothing the code doesn't say. Doc comments (and the plain comments that serve as docs where a language has no doc syntax: Go file scope and struct fields, Python module and class attributes), pragmas, banners, questions, comments with code symbols or quotes in them, comments naming an identifier the statement lacks, and any comment carrying a why (because, otherwise, workaround, a URL, an issue number), a constraint (not, only, unless, before) or a warning (careful, subtle) are exempt. Inflection is ignored (parsed matches parse_header) but abbreviations are not (max is not maximum)
SLOP043 verbosity Comment that runs long B, on TS, TSX, Python, Go, Rust en, pt-BR A plain comment block (consecutive comment lines count as one) of more than 40 words. A reason fits in a sentence or two; a comment that needs three full lines is narrating the code or carrying a design note that belongs in a doc comment, the README or the commit message. Doc comments, godoc (any Go comment outside a function body), license headers, generated files and commented-out code are exempt
SLOP044 artifact Boilerplate or empty page title B, on HTML en, pt-BR A <title>Document</title> (the editor's ! expansion left in place) or an empty <title>

Every rule is exactly one of three states, --list-rules prints the DEFAULT column so you can check any given rule at a glance:

  • Tier A, on by default (12 rules): mechanical artifacts (SLOP001–009, SLOP011–013) with no legitimate reading. A finding here fails the run (exit 1) and blocks CI.
  • Tier B, on by default (28 rules): everything else except SLOP010. Judgment calls (density and style checks on prose, stdlib/structure heuristics) that warn without ever exiting 1. Expect some noise; silence what you don't want with ignore/--ignore by code or group.
  • Tier B, off by default (1 rule): SLOP010, gated behind --check-imports because of its false-positive risk with private registries and dynamic imports.

Tier is a fixed property of each rule, and select/ignore can't change it. What you can change is which tier the run fails on: fail-on-tier = "B" in stopslop.toml (or --fail-on-tier B) puts every finding on the exit-1 path. CHANGELOG.md records which rules changed tier between releases.

Findings that have one concrete replacement print it on a second line:

src/util.ts:14:11 SLOP037 deep clone via a JSON round trip
    fix: use `structuredClone(value)`

--format json carries the same text in a fix field, omitted when a rule flags a document-wide pattern with no single substitutable span.

Note on SLOP007: a bare x as unknown is not flagged on its own: it's a legitimate first step in TypeScript's narrowing idiom. Only the chained form, x as unknown as T, is flagged, since that's the pattern that fully defeats the type checker.

Prose linting

stopslop also lints .md, .mdx, .txt, .rst, and .html/.htm files: same binary, same deterministic regex/structural matching, no LLM involved in the scan.

HTML is parsed with tree-sitter-html, and the rules see what a reader sees: visible text, HTML comments, and href/src attribute values. Everything else is blanked, including <script>, <style>, <pre>, <code>, <textarea>, <template>, <svg>, <math>, and <noscript> bodies. Django/Jinja {{ … }}, {% … %}, and {# … #} are blanked before parsing too. Each leaf block element (<p>, <div>, <blockquote>, <td>) is one paragraph for the rhythm, recap, synonym, and uniformity rules; list items, headings, table cells, and form controls never are, and a <footer> is never the ending. <strong>/<b> count as bold, inline <code> counts as words, and &mdash;, &#8212;, and the curly-quote entities are read as the characters they encode. &ndash; and every other entity stay blank.

SLOP011–013 catch mechanical, high-confidence artifacts (leftover chat-turn phrasing including reasoning-chain scaffolding and acknowledgment loops, citation-tool tokens, unfilled placeholders) and are Tier A: a finding there fails the run. SLOP014, SLOP018, and the formulaic-shape rules SLOP022–025 and SLOP029 are on by default too but Tier B, warn-only: judgment calls the tool still surfaces every run, just without the power to fail CI. SLOP018 flags every mid-prose dash outright (the one exemption is a block-opening attribution dash like — Oscar Wilde).

The rest are document-wide density and style checks, also on by default: hedging, overused vocabulary, rhetorical parallelism, boldface overuse, smart quotes, heading formatting, promotional register, hyphen stacking, sentence length, synonym rotation, outline filler, change-narrating docs, colon reveals, filler and adverb density, weak-verb phrasing, dramatic fragmentation, and mechanical uniformity. SLOP041 is the one rule in this list that measures statistics (burstiness, vocabulary diversity, trigram repetition) instead of matching a phrase. It catches templated prose that rotates its vocabulary just enough to slide past every phrase-based rule. These are judgment calls rather than mechanical certainties, so they're warn-only. Silence the ones you don't want by code (--ignore SLOP015) or by group (--ignore verbosity). Expect some noise from them: a finding here is a lead to investigate rather than a verdict. As with the rest of stopslop, this is a writing-quality gate, not a claim about who or what wrote the text: every rule flags a concrete pattern (a stale phrase, an unfilled slot, a density threshold, a document-level statistic), never "this is AI-generated."

Every rule runs every natural-language panel it declares, on every document, by default: nothing to configure, nothing to detect. Lang is the file syntax (Markdown, MDX, ...); NatLang is a separate axis for which lexicons a rule's phrase panels actually cover, listed per rule in the NL column above. Structural and statistical rules (AST shape, punctuation, density) need no lexicon and already run on pt-BR text. Phrase-panel rules gain a pt-BR panel one rule at a time, each proven by a fixture under tests/fixtures/markdown/pt-br/ before the rule may list pt-BR; SLOP014 (cliché phrases), SLOP016 (vocabulary), and SLOP032 (hyphenated-compound overuse) still stay English-only, and issue #30 tracks the rest. pt and pt-PT both resolve to the same Brazilian lexicon as pt-BR, a best-effort alias rather than a separate European-Portuguese panel. An HTML page that declares <html lang="..."> narrows its own run to that language when the config allows it (.rst docinfo and Markdown front matter carry no such hint yet). SLOP033's overlong-sentence cap rises to 57 words once a run is Portuguese-only (language = "pt-BR", measured against English's 50 on matched corpora). SLOP041's thresholds hold as measured (Portuguese trips them less often than English, not more); SLOP043 and SLOP029's caps are still unmeasured for Portuguese, and language = "pt-BR" in stopslop.toml restricts a run to the Portuguese panels only.

Suppression

Two escape valves, both plain comments so they work in any language's comment syntax:

  • // ai-slop-ignore: suppresses findings on that line and the line below it (so it works whether the comment is trailing or sits above the flagged line).
  • // ai-slop-ignore-file: anywhere in the file, drops every finding in that file.

In Markdown/MDX/Text/reST/HTML files, use the HTML comment form instead: <!-- ai-slop-ignore --> / <!-- ai-slop-ignore-file -->, with the same two-line and whole-file suppression semantics.

Bare, either directive suppresses every rule. Add : CODE,CODE (commas or spaces both work) to scope it to specific rules, or to a group name:

// ai-slop-ignore: SLOP002,SLOP004
// Certainly! Generated by ChatGPT — kept verbatim as a fixture for this rule's own test
<!-- ai-slop-ignore-file: SLOP018 

Read the rest on GitHub

Scan report · 2026-09-13
  • Prohibited terms or links
  • Repository eligibility
  • slopscore.md paperwork
  • Content policy
  • Risk review

0 comments

log in to comment.

report this listinglog in to report