A deterministic linter, written in Rust, for the tells AI leaves in code and prose: 57 rules, one static binary, no model at scan time.
cargo install stopslopFrom the latest main, or from a local checkout:
cargo install --git https://github.com/mgiovani/stopslop
cargo install --path .stopslop . # lint the current directory
stopslop --since origin/main # lint only the files changed on this branchtests/fixtures/typescript/slop_attribution.ts:1:1 SLOP004 AI attribution / chat-export artifact in comment
tests/fixtures/typescript/slop_elision.ts:3:3 SLOP001 elision comment may have replaced real code
tests/fixtures/markdown/slop_residue.md:3:1 SLOP011 unedited assistant-response residue in prose
fix: delete the sentence
Tier A findings exit 1 and fail CI. Tier B findings warn. See usage for formats (text, JSON, SARIF, Markdown), baselines and exit codes.
- Reads what other linters skip. ESLint, Ruff, and Clippy treat comment and string content as trivia, which is where
// ... rest of code unchangedand a leaked "Certainly! Here's..." preamble end up. See why. - Deterministic. Every rule is a tree-sitter AST match or a regex over extracted comment, string or prose text. Same input, same output, with no LLM call, API call, or network access at scan time.
- CI-ready tiers. Tier A is mechanical and fails the run; Tier B warns. Tier C stays opt-in until a labelled corpus has scored it.
- Code, prose, stylesheets, and images. Source code and documents,
.cssand.scssstylesheets (thedesigngroup reads generated-UI tells, see style linting), plus the metadata of PNG, JPEG and WebP images. - English and Brazilian Portuguese. Phrase panels for both run by default.
- Measured.
just corpusscores every rule against labelled human and AI corpora; see benchmarks. - Fast and quiet to adopt. One binary and no config to start.
--stagedand--sincelint only a diff, and a baseline grandfathers old findings.
57 rules in 9 groups. --list-rules prints every rule with its group, tier, and state.
| 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 |
provenance |
Embedded image metadata that names how or by what an image was made |
design |
Visual tells of generated UI, read from CSS, style=, and utility classes |
The per-rule table is in docs/rules.md.
| Tier | Default | Effect |
|---|---|---|
| A | on (14 rules) | A finding exits 1 and blocks CI. Mechanical artifacts with no legitimate reading. |
| B | on (37 rules) or off (3 rules) | Judgment calls that warn and never exit 1. fail-on-tier = "B" makes them fail. |
| C | off (3 rules) | Thresholds not yet scored against a labelled corpus. Opt in with --extend-select. |
# stopslop.toml
ignore = ["SLOP009", "verbosity"] # rule codes or groups to subtract
extend-select = ["SLOP033"] # add a rule on top of the defaults
fail-on-tier = "A" # lowest tier that exits 1
[per-file-ignores]
"docs/**" = ["SLOP036"]stopslop --help-config prints an annotated file with every key. Details, user-defined rules, and --check-imports are in docs/configuration.md. To silence one finding, put // ai-slop-ignore above it; see suppression.
stopslop --staged # pre-commit hook
stopslop --since origin/main # pull request check
stopslop --format sarif . # GitHub code scanning- Not an AI-origin verdict. A rule may name a span as a known AI tell so you can rewrite it. stopslop never scores a whole file as written by AI and never runs a model.
- Not a correctness checker. It does not run your code or detect hallucinated methods.
[[custom-rule]]is a phrase matcher, not a plugin system.
The full list is in docs/why.md.
Read AGENTS.md for the architecture, the checklist for adding a rule, and the test gates.
MIT (see LICENSE).
stopslop's own CI fails if its source contains slop: every push runs cargo run --quiet -- . against the whole repo, prose included, alongside cargo fmt, cargo clippy, and cargo test. Tier A findings fail the build; Tier B findings print as warnings, the same contract users get.




