Quality gates for AI-assisted codebases โ catch the slop LLMs leave behind.
Project description
๐ชฃ Slop-Mop
Quality gates for AI-assisted codebases. Not a silver bullet โ just a mop.
The code generated by frontier LLMs shares the same features. These days, the majority of those features are positive, but there are still remnants from agent training that result in a set of undesirable outcomes from agentic LLMs โ especially when working with very small development teams or "vibe coded" projects.
The frontier agents used to generate code were all effectively trained to "accomplish the task at any cost." This makes them great at accomplishing small things with blinders on, but dangerous for the long-term stability of a repository.
The modern development process has turned into a game of whack-a-mole where we're trying to use the output of the agents while also catching LLMs in instances of shortsightedness, deception, overconfidence, and laziness. Instead of repeating yourself in chat ad nauseam, let slop-mop do that steering for you.
Not only will slop-mop catch many of the most egregious examples of these behaviors, but it will also tell the agent the precise mistake made and exactly how to fix it. This is a new approach for agentic development โ turning a "bug" (relentless task accomplishment) into a feature (relentless code quality improvement).
Quick Start
# Install (once per machine)
pipx install slopmop # recommended โ isolated, no dep conflicts
# or: pip install slopmop
# Set up your project
sm init # auto-detects languages, writes .sb_config.json
# Run quality gates
sm validate commit # fix what it finds, commit when green
sm init auto-detects Python, JavaScript, or both and writes a .sb_config.json with applicable gates enabled.
The Loop
Development with slop-mop follows a single repeated cycle:
sm validate commit โ see what fails โ fix it โ repeat โ commit
When a gate fails, the output tells you exactly what to do next:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ค AI AGENT ITERATION GUIDANCE โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Profile: commit โ
โ Failed Gate: deceptiveness:py-coverage โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ NEXT STEPS: โ
โ โ
โ 1. Fix the issue described above โ
โ 2. Validate: sm validate deceptiveness:py-coverage โ
โ 3. Resume: sm validate commit โ
โ โ
โ Keep iterating until all the slop is mopped. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
This is purpose-built for AI agents. The guidance is machine-readable, the iteration is mechanical, and the agent never has to wonder what to do next. It saves tokens (no flailing), saves CI dollars (catch it locally), and keeps the codebase habitable long-term.
Use sm status for a report card of all gates at once.
Why These Categories?
Gates aren't organized by language โ they're organized by the failure mode they catch. These are the four ways LLMs reliably degrade a codebase:
๐ด Overconfidence
"It compiles, therefore it's correct."
The LLM generates code that looks right, passes a syntax check, and silently breaks at runtime. These gates verify that the code actually works.
| Gate | What It Does |
|---|---|
overconfidence:py-tests |
๐งช Runs pytest โ code must actually pass its tests |
overconfidence:py-static-analysis |
๐ mypy strict โ types must check out |
overconfidence:py-types |
๐ฌ pyright strict โ second opinion on types |
overconfidence:js-tests |
๐งช Jest test execution |
overconfidence:js-types |
๐๏ธ TypeScript type checking (tsc) |
overconfidence:deploy-script-tests |
๐ Validates deploy scripts |
๐ก Deceptiveness
"Tests pass, therefore the code is tested."
The LLM writes tests that assert nothing, mock everything, or cover the happy path and call it done. Coverage numbers look great. The code is still broken.
| Gate | What It Does |
|---|---|
deceptiveness:py-coverage |
๐ Whole-repo coverage (80% default threshold) |
deceptiveness:py-diff-coverage |
๐ Coverage on changed lines only (diff-cover) |
deceptiveness:bogus-tests |
๐ง AST analysis for tests that assert nothing |
deceptiveness:js-coverage |
๐ JavaScript coverage analysis |
deceptiveness:js-bogus-tests |
๐ญ Bogus test detection for JS/TS |
๐ Laziness
"It works, therefore it's done."
The LLM solves the immediate problem and moves on. Formatting is inconsistent, dead code accumulates, complexity creeps upward, and nobody notices until the codebase is incomprehensible.
| Gate | What It Does |
|---|---|
laziness:py-lint |
๐จ autoflake, black, isort, flake8 (supports auto-fix ๐ง) |
laziness:js-lint |
๐จ ESLint + Prettier (supports auto-fix ๐ง) |
laziness:complexity |
๐ Cyclomatic complexity (max rank C) |
laziness:dead-code |
๐ Dead code detection via vulture (โฅ80% confidence) |
laziness:template-syntax |
๐ Jinja2 template validation |
laziness:js-frontend |
โก Quick ESLint frontend check |
๐ต Myopia
"My change is fine. Why would I look at the bigger picture?"
The LLM has a 200k-token context window and still manages tunnel vision. It duplicates code across files, ignores security implications, and lets functions grow unbounded because it can't see the pattern.
| Gate | What It Does |
|---|---|
myopia:loc-lock |
๐ File and function length limits |
myopia:source-duplication |
๐ Code clone detection (jscpd) |
myopia:string-duplication |
๐ค Duplicate string literal detection |
myopia:security-scan |
๐ bandit + semgrep + detect-secrets |
myopia:security-audit |
๐ Full security audit (code + pip-audit) |
PR Gates
| Gate | What It Does |
|---|---|
pr:comments |
๐ฌ Checks for unresolved PR review threads |
Profiles
Profiles bundle gates into workflows. Use profiles, not individual gates:
| Profile | Gates | When to Use |
|---|---|---|
commit |
17 gates โ all overconfidence, deceptiveness, laziness, myopia checks | Before every commit |
pr |
19 gates โ all commit gates + PR comments + diff-coverage | Before opening or updating a PR |
quick |
2 gates โ lint + security scan | Fast feedback during development |
python |
5 gates โ Python-specific subset | Language-focused validation |
javascript |
5 gates โ JS/TS-specific subset | Language-focused validation |
quality |
5 gates โ complexity, duplication, loc-lock | Code quality only |
security |
1 gate โ full security audit | Security-focused validation |
JS gates auto-skip when no JavaScript is detected.
Getting Started: The Remediation Path
Most projects won't pass all gates on day one. That's expected. Here's the ramp:
1. Initialize
sm init # auto-detects everything, writes .sb_config.json
2. See Where You Stand
sm validate commit # run all gates, see what fails
sm status # full report card
3. Disable What You're Not Ready For
sm config --disable laziness:complexity # too many complex functions right now
sm config --disable deceptiveness:py-coverage # coverage is at 30%, not 80%
sm validate commit # get the rest green first
4. Fix Everything That's Left
Iterate: run sm validate commit, fix a failure, run again. The iteration guidance tells you exactly what to do after each failure.
5. Install Hooks
sm commit-hooks install commit # pre-commit hook runs quality gates
sm commit-hooks status # verify hooks are installed
Now every git commit runs slop-mop. Failed gates block the commit.
6. Re-enable Gates Over Time
sm config --enable laziness:complexity # refactored enough, turn it on
sm config --enable deceptiveness:py-coverage # coverage is at 75%, set threshold to 70
7. Let Agents Vibe-Code
With hooks in place, agents can write code freely. Slop-mop catches the slop before it reaches the repo. This saves tokens (no back-and-forth debugging), saves CI money (catch it locally), and keeps the codebase survivable long-term.
Configuration
sm config --show # show all gates and their status
sm config --enable <gate> # enable a disabled gate
sm config --disable <gate> # disable a gate
sm config --json <file> # bulk update from JSON
Include / Exclude Directories
sm config --exclude-dir myopia:generated # skip generated code
sm config --include-dir overconfidence:src # only check src/
include_dirs: whitelist โ only these dirs are scannedexclude_dirs: blacklist โ always skipped, takes precedence
.sb_config.json
Edit directly for per-gate configuration:
{
"version": "1.0",
"default_profile": "commit",
"python": {
"gates": {
"coverage": { "threshold": 80 },
"tests": { "test_dirs": ["tests"] }
}
},
"quality": {
"exclude_dirs": ["generated", "vendor"]
}
}
CI Integration
GitHub Actions
name: slop-mop
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install slopmop
- run: sm validate commit
- if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
run: sm validate pr:comments
Check CI Status Locally
sm ci # current PR
sm ci 42 # specific PR
sm ci --watch # poll until CI completes
Architecture
Slop-mop installs as a normal package and is configured per-project via .sb_config.json. The sm command is on your PATH once and works in any repo.
Tool resolution order โ sm uses your project's tools when available:
<project_root>/venv/bin/<tool>or.venv/bin/<tool>โ project-local venv (highest priority)$VIRTUAL_ENV/bin/<tool>โ currently activated venv- System PATH โ sm's own bundled tools (via pipx)
This means if your project has its own pytest (with plugins like pytest-django), sm uses it. Otherwise, sm falls back to its own.
Submodule alternative: If you need strict version pinning, add slop-mop as a git submodule and invoke python -m slopmop.sm directly. Supported but not recommended for most projects.
Development
# Working on slop-mop itself
pip install -e .
sm validate --self # dogfooding โ sm validates its own code
pytest
See CONTRIBUTING.md for the process of adding new gates.
Further Reading
๐ A Hand for Daenerys: Why Tyrion Is Missing from Your Vibe-Coding Council โ the article that started this project.
License
Slop-Mop Attribution License v1.0 โ free to use, modify, and redistribute with attribution.
P.S. Other than this line in the readme and a few scattered lines here and there, nothing in this project was written by a human. It is, for better or worse, the result of living under the slop-mop regime.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file slopmop-0.4.1.tar.gz.
File metadata
- Download URL: slopmop-0.4.1.tar.gz
- Upload date:
- Size: 146.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d6872ba962c149d97e2476a1900eb831e23349f04633ebe535e9961ee460b445
|
|
| MD5 |
25bbfe1e6e53687dc2659f3af06a651d
|
|
| BLAKE2b-256 |
1bb50f9c8111b5d72f7656e3e3d002bffa9e7ffa63d4ceba891dd8e63dd17137
|
Provenance
The following attestation bundles were made for slopmop-0.4.1.tar.gz:
Publisher:
release.yml on ScienceIsNeato/slop-mop
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
slopmop-0.4.1.tar.gz -
Subject digest:
d6872ba962c149d97e2476a1900eb831e23349f04633ebe535e9961ee460b445 - Sigstore transparency entry: 999039937
- Sigstore integration time:
-
Permalink:
ScienceIsNeato/slop-mop@77814ba266a0a00f2ef56392e5f5d541a75b85dc -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/ScienceIsNeato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@77814ba266a0a00f2ef56392e5f5d541a75b85dc -
Trigger Event:
push
-
Statement type:
File details
Details for the file slopmop-0.4.1-py3-none-any.whl.
File metadata
- Download URL: slopmop-0.4.1-py3-none-any.whl
- Upload date:
- Size: 178.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28d524494968aa0fa49984c7afde3894b1048245e3c0f5db4afa23cff2a012df
|
|
| MD5 |
1f88f11bdf83bb9746acc261468bb338
|
|
| BLAKE2b-256 |
f8720afb53363f9f14822ba7d09d76781490cb1e9b392ff0a13e5ab0e9ce74d3
|
Provenance
The following attestation bundles were made for slopmop-0.4.1-py3-none-any.whl:
Publisher:
release.yml on ScienceIsNeato/slop-mop
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
slopmop-0.4.1-py3-none-any.whl -
Subject digest:
28d524494968aa0fa49984c7afde3894b1048245e3c0f5db4afa23cff2a012df - Sigstore transparency entry: 999039983
- Sigstore integration time:
-
Permalink:
ScienceIsNeato/slop-mop@77814ba266a0a00f2ef56392e5f5d541a75b85dc -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/ScienceIsNeato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@77814ba266a0a00f2ef56392e5f5d541a75b85dc -
Trigger Event:
push
-
Statement type: