A lightweight CLI for catching slop in modern codebases before it hardens into tech debt.
Project description
SlopSniff
A lightweight CLI for catching code-quality drift ("slop") before it hardens into team-wide tech debt.
npm Usage
Install/run from JavaScript projects via npm:
npx slopsniff-cli .
Notes:
- The npm package is a wrapper around the Python CLI.
- It runs
slopsniffviauv tool run --from slopsniff .... - On macOS/Linux, it will attempt to install
uvautomatically if missing.
What it catches
| Pattern | Slop | Better |
|---|---|---|
| Fallback defaults Silent primitives that mask missing config |
timeout = os.getenv("TIMEOUT", 0)
const retries = process.env.RETRIES || 0;
|
timeout = require_env("TIMEOUT")
const retries = requireEnv("RETRIES");
|
| Catch-all primitive returns Flattens every failure into one silent shape |
except Exception:
return []
catch (e) { return null; }
|
except TimeoutError:
logger.warning("upstream timeout")
raise
catch (e) {
if (e instanceof RateLimitError) { ... }
throw e;
}
|
| Exposed secrets Credentials committed in source or docs |
API_KEY = "sk-proj-abc123..."
|
API_KEY = os.environ["API_KEY"]
|
| Large files & functions Monoliths that resist review and testing |
|
|
| Duplicate functions Copy-pasted logic across files |
|
|
| Helper sprawl Vague catch-all files and versioned copies |
|
|
Local Setup (Open Source Dev)
git clone https://github.com/joshuagilley/slopsniff
cd slopsniff
uv sync --dev
pre-commit install
Quick sanity run:
uv run pytest
uv run ruff check .
env PYTHONPATH=src uv run python -m slopsniff.cli . --fail-threshold 30
Notes:
- Pre-commit runs
ruff,ruff-format,slopsniff, andpytest. - Terminal output uses Rich. Use
--format jsonfor machine output. - For local runs, prefer
env PYTHONPATH=src uv run python -m slopsniff.cli ....
Basic Usage
# Scan current directory
env PYTHONPATH=src uv run python -m slopsniff.cli .
# Scan a specific path
env PYTHONPATH=src uv run python -m slopsniff.cli ./src
# JSON output for CI/machines
env PYTHONPATH=src uv run python -m slopsniff.cli . --format json
# Override thresholds ad hoc
env PYTHONPATH=src uv run python -m slopsniff.cli . --max-file-lines 300 --max-function-lines 40
Configuration (slopsniff.json)
SlopSniff auto-loads slopsniff.json from the scan root (the path you pass to slopsniff).
You can tune scoring thresholds, file selection, and enabled rules in one place.
Example:
{
"fail-threshold": 20,
"max-file-lines-warning": 400,
"max-file-lines-high": 800,
"max-function-lines-warning": 50,
"max-function-lines-high": 100,
"verbose": false,
"include-extensions": [".py", ".js", ".ts", ".tsx", ".jsx", ".vue", ".html"],
"large-file-extensions": [".py", ".js", ".ts", ".tsx", ".jsx", ".vue"],
"exclude-files": ["temp_slop_examples.py", "src/fixtures/example.py"],
"exclude-dirs": [
".git",
"node_modules",
".venv",
"tests",
"dist",
"build"
],
"include": [
"fallback-defaults",
"exposed-secrets",
"large-function",
"large-file",
"duplicate-functions",
"helper-sprawl"
]
}
Rule IDs for include:
fallback-defaultsexposed-secretslarge-functionlarge-fileduplicate-functionshelper-sprawl
Notes:
- CLI flags still work and override file values (for example,
--fail-threshold). - If
includeis omitted, all rules run. exclude-filesaccepts either bare filenames or scan-root-relative paths.- Unknown keys and unknown rule IDs fail fast with clear errors.
Contributing and Commits
Standard flow:
- Create a feature branch from
main. - Make changes.
- Run checks locally:
uv run pytest uv run ruff check . env PYTHONPATH=src uv run python -m slopsniff.cli . --fail-threshold 30
- Commit with a clear message.
- Open a PR and merge after CI passes.
Release Process
Publishing is handled by .github/workflows/publish.yml.
It runs on GitHub Release published (not on tag push alone).
Recommended: one-command release script
From repo root, on main, with a clean working tree:
./scripts/release.py 0.1.9
# or:
uv run python scripts/release.py v0.1.9
What it does:
- Pulls
main. - Bumps version in
pyproject.tomlandsrc/slopsniff/__init__.py. - Runs
uv lock. - Commits
chore: release X.Y.Z. - Pushes
main. - Tags
vX.Y.Zand pushes the tag. - Creates/publishes a GitHub release with
gh release create.
Useful flags:
--dry-run--no-pull--allow-dirty--notes-file PATH--expect-repo OWNER/REPO
Optional guard:
- Set
SLOPSNIFF_RELEASE_EXPECT_REPO=joshuagilley/slopsniffto prevent accidental release from a fork clone.
If release/publish fails
HTTP 400from PyPI: that version already exists; bump to a new version and release again.HTTP 422fromgh release create: release already exists for that tag. Re-run workflow for that release if needed.- Re-running old releases uses the same tagged commit; it does not pick up newer
main.
Minimal Architecture Notes
Pipeline:
- Walk repo and collect included files.
- Parse functions (
astfor Python, heuristic parser for JS/TS/TSX/JSX/Vue). - Run per-file rules.
- Run cross-file rules.
- Aggregate findings and score.
- Report (
terminalvia Rich orjson) and exit non-zero on threshold fail.
Key paths:
src/slopsniff/cli.py— CLI entrypointsrc/slopsniff/scanner.py— orchestrationsrc/slopsniff/rules/— rule implementationssrc/slopsniff/reporters/— terminal/json outputscripts/release.py— scripted release flow
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 slopsniff-0.1.15.tar.gz.
File metadata
- Download URL: slopsniff-0.1.15.tar.gz
- Upload date:
- Size: 23.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
480c52b422ee8762845be481dbf1afc8c198b37fab7b9e9203578633d7d7ce5c
|
|
| MD5 |
37f2e3190e92677bc6fd7e60c93cf814
|
|
| BLAKE2b-256 |
fc1e0bb5d386b4c0a8d57ac20bbc4bacbe0611da0fe84af7daec13eab58da8ac
|
Provenance
The following attestation bundles were made for slopsniff-0.1.15.tar.gz:
Publisher:
publish.yml on joshuagilley/slopsniff
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
slopsniff-0.1.15.tar.gz -
Subject digest:
480c52b422ee8762845be481dbf1afc8c198b37fab7b9e9203578633d7d7ce5c - Sigstore transparency entry: 1173496815
- Sigstore integration time:
-
Permalink:
joshuagilley/slopsniff@80cbc44ebad52c98e91f5b7c1d2880488eb004de -
Branch / Tag:
refs/tags/v0.1.15 - Owner: https://github.com/joshuagilley
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@80cbc44ebad52c98e91f5b7c1d2880488eb004de -
Trigger Event:
release
-
Statement type:
File details
Details for the file slopsniff-0.1.15-py3-none-any.whl.
File metadata
- Download URL: slopsniff-0.1.15-py3-none-any.whl
- Upload date:
- Size: 21.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 |
f5e5f991e5b0cf5dadced722102d862e43fa9c16c82cfe8b278b8492c910feed
|
|
| MD5 |
73d18bc057626aefa1f76dcbe36bb0ce
|
|
| BLAKE2b-256 |
d9f279c5ccdd15c6bc3977237441edeb67ee5e5c2f32314561f0f0591ab8fc36
|
Provenance
The following attestation bundles were made for slopsniff-0.1.15-py3-none-any.whl:
Publisher:
publish.yml on joshuagilley/slopsniff
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
slopsniff-0.1.15-py3-none-any.whl -
Subject digest:
f5e5f991e5b0cf5dadced722102d862e43fa9c16c82cfe8b278b8492c910feed - Sigstore transparency entry: 1173496920
- Sigstore integration time:
-
Permalink:
joshuagilley/slopsniff@80cbc44ebad52c98e91f5b7c1d2880488eb004de -
Branch / Tag:
refs/tags/v0.1.15 - Owner: https://github.com/joshuagilley
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@80cbc44ebad52c98e91f5b7c1d2880488eb004de -
Trigger Event:
release
-
Statement type: