Skip to main content

Quality gates for AI-assisted codebases โ€” catch the slop LLMs leave behind.

Project description

๐Ÿชฃ Slop-Mop

PyPI version CI Python 3.10+ License

Quality gates for AI-assisted codebases. Not a silver bullet โ€” just a mop.

Slop-Mop

LLMs are trained to close tickets, not steward codebases. They cargo-cult patterns they can't see across files, duplicate code they don't remember writing, and accumulate technical debt in predictable, repeatable ways. Left unchecked, you end up with a kingdom of ashes.

Slop-Mop is Tyrion in a box โ€” automated quality gates that catch the failure modes AI agents are most prone to: overconfidence, deceptiveness, laziness, and myopia. Bolt it on, fix what it finds, install hooks, and let your agents vibe-code with guardrails instead of prayers.

๐Ÿ“– A Hand for Daenerys: Why Tyrion Is Missing from Your Vibe-Coding Council


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

That's it. Three commands. Auto-detects Python, JavaScript, or both. Enables applicable gates, disables the rest.


The Loop

The entire workflow is one loop:

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 scanned
  • exclude_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:

  1. <project_root>/venv/bin/<tool> or .venv/bin/<tool> โ€” project-local venv (highest priority)
  2. $VIRTUAL_ENV/bin/<tool> โ€” currently activated venv
  3. 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.


License

Slop-Mop Attribution License v1.0 โ€” free to use, modify, and redistribute with attribution.


Other than a few 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slopmop-0.2.1.tar.gz (130.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slopmop-0.2.1-py3-none-any.whl (160.2 kB view details)

Uploaded Python 3

File details

Details for the file slopmop-0.2.1.tar.gz.

File metadata

  • Download URL: slopmop-0.2.1.tar.gz
  • Upload date:
  • Size: 130.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for slopmop-0.2.1.tar.gz
Algorithm Hash digest
SHA256 ac597c347cc40d1f04b4ad9b75ca45b50350013d3818898ccea1d501495a841d
MD5 c6713871d8a93e44a1b38199d70ed080
BLAKE2b-256 5dd4923b3b362575fa927701cfbe706446f195495e16381162b2e2f6518195de

See more details on using hashes here.

Provenance

The following attestation bundles were made for slopmop-0.2.1.tar.gz:

Publisher: release.yml on ScienceIsNeato/slop-mop

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file slopmop-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: slopmop-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 160.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for slopmop-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5fe1496474c3293ed8998317c0ff6fa019d9f96039a07d3b7e33e17633e3bb2d
MD5 dce425e9dce3c9f6a47399aaeaefee4a
BLAKE2b-256 f98b515bb389abd1807fe5bc8e74dba74a5273027e4eced30caf362466e34c68

See more details on using hashes here.

Provenance

The following attestation bundles were made for slopmop-0.2.1-py3-none-any.whl:

Publisher: release.yml on ScienceIsNeato/slop-mop

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page