Skip to main content

Agentic code quality linter — catches slop before it becomes architectural rot

Project description

slop

A code quality linter for codebases where AI agents are writing most of the diffs.

PyPI Python License

Static analysis tools got their defaults from codebases where a productive human wrote maybe 100 lines on a busy day and another human reviewed every one. An agent can drop that much into a single file before emitting its first status message, and the structural damage (deep coupling, WMC-heavy classes, files that grow 500 LOC in a week) lands inside one session rather than accumulating over quarters. The usual review cadence does not catch it. slop is calibrated for that pace.

The metrics themselves are not new. Cyclomatic complexity (McCabe 1976), the CK suite for classes (Chidamber and Kemerer 1994), package distance from the Main Sequence (Martin 1994), churn-weighted hotspots (Tornhill 2015): all well-cited, all mostly ignored in day-to-day workflows because they were tuned for human timescales. slop wraps them behind one CLI with thresholds that assume a different pace of change.

Example

$ slop lint

slop 0.5.0 — scanning .

complexity
  cyclomatic
    ✗ src/pipeline/ingest.py:44 process_batch — CCX 18 exceeds 10
    ✗ src/pipeline/ingest.py:112 _normalize_rows — CCX 14 exceeds 10
    ✗ src/store/frame.py:204 append_partition — CCX 11 exceeds 10

  cognitive
    ✗ src/pipeline/ingest.py:44 process_batch — CogC 26 exceeds 15
    ✗ src/store/frame.py:204 append_partition — CogC 21 exceeds 15

  6 violations, 142 checked

hotspots (14 days ago)
  ✗ src/lifecycle/tasks/write.py — CCX=41, growth +556 LOC
  ✗ src/pipeline/transformation.py — CCX=45, growth +367 LOC
  2 violations

packages
  ⚠ src/config — Zone of Pain (I=0.12, A=0.00)
  ⚠ src/core/distributed/dag — Zone of Pain (I=0.18, A=0.05)
  ⚠ src/core/transform — Zone of Pain (I=0.09, A=0.03)
  3 advisories

deps
  ✓ clean, 55 checked

class
  coupling
    ✗ tests/v2/test_pdrf_types.py:12 PdrfTestSuite — CBO 11 exceeds 8

  1 violation, 8 checked

orphans (disabled)
  ℹ skipped (enable in .slop.toml)

────────────────────────────────────────
9 violations | 3 advisories | 8 rules checked | FAIL

Exit code is 0 when clean, 1 on violations, 2 on configuration or runtime error. Works in CI, pre-commit hooks, and interactively.

Install

pip install agent-slop-lint

slop shells out to rg, fd, and git. Install those via your system package manager (apt install ripgrep fd-find git, brew install ripgrep fd git, or equivalent) and run slop doctor to verify.

Full per-platform install steps, CI recipes, pre-commit wiring, and the agent skill are in the setup guide.

Rules

Rule Default Measures Source
complexity.cyclomatic CCX > 10 Per-function path count McCabe 1976
complexity.cognitive CogC > 15 Per-function reading difficulty Campbell 2018
complexity.weighted WMC > 40 Per-class aggregate method complexity Chidamber and Kemerer 1994
halstead.volume V > 1500 Per-function information content (Length × log2 Vocabulary) Halstead 1977
halstead.difficulty D > 30 Per-function operator/operand density Halstead 1977
npath NPath > 400 Per-function acyclic execution path count Nejmeh 1988
hotspots 14-day window Files that are complex AND growing fast Tornhill 2015
packages D' > 0.7 Package design distance from the Main Sequence Martin 1994
deps any cycle Dependency cycles between modules Tarjan 1972
orphans disabled Unreferenced symbols (advisory)
class.coupling CBO > 8 Classes coupled to too many other classes Chidamber and Kemerer 1994
class.inheritance.depth DIT > 4 Inheritance hierarchies that are too deep Chidamber and Kemerer 1994
class.inheritance.children NOC > 10 Base classes with too many direct subclasses Chidamber and Kemerer 1994

Per-threshold explanations, when to raise them, and the default / lax / strict profiles live in the configuration reference.

Why a 14-day hotspot window

Tornhill's original work used a 1-year window, tuned for release cycles where a file you had not touched in 9 months was stable and a file you had been touching for 9 months was probably structurally important. Agent workflows collapse that timescale. A file can go from 200 LOC to 800 LOC in a week, and the architectural decisions compounding inside that growth are the ones worth catching early rather than a year later when the file is already unrecoverable. The 14-day default rewards recency. Widen rules.hotspots.since to "90 days ago" for human-pace repos.

Language support

Language Extensions Complexity Hotspots Packages Deps Class
Python .py yes yes yes yes yes
JavaScript .js, .mjs, .cjs yes yes yes yes
TypeScript .ts, .tsx yes yes yes yes
Go .go yes yes yes yes yes
Rust .rs yes yes yes
Java .java yes yes yes yes
C# .cs yes yes yes yes

Martin's package metrics currently only run on Go and Python. Files in other languages are silently excluded from that rule, not errored. Every other rule runs across all seven languages.

Configuration

slop walks upward from the current directory looking for .slop.toml first and then pyproject.toml with a [tool.slop] table, the same discovery ruff and mypy use. When a config is discovered, its root key resolves relative to the config file's directory, so root = "src" in ~/project/.slop.toml always points at ~/project/src regardless of which subdirectory you invoked slop from. --config and --root on the CLI override both.

Generate a starter config:

slop init          # balanced defaults
slop init lax      # legacy or gradual adoption
slop init strict   # greenfield or quality-focused

Every threshold, the intent behind it, and the three profiles in full are documented in the configuration reference.

CLI

slop lint                         Run all enabled rules (default command)
slop check <category|rule>        Run one category or rule
slop init [profile]               Generate .slop.toml
slop doctor                       Check fd, rg, git are installed
slop hook                         Install a git pre-commit hook
slop skill <dir>                  Install the bundled agent skill
slop rules                        List rules with thresholds
slop schema                       Config schema as JSON

Run slop --help for the full flag list, or slop <command> --help for per-command options. Output formats are --output human (default), --output json for CI and agent consumption, and --output quiet for one-line summaries.

Architecture

slop is a thin orchestration layer. Metric computation lives in aux-skills, a sibling package that ships deterministic kernels built on tree-sitter, ripgrep, fd, and git. slop wraps those kernels with declarative config, threshold checking, human/JSON/quiet output, and CI exit codes.

When aux-skills gains a new metric kernel, slop gains a new rule with zero computation work.

Acknowledgments

slop implements metrics from established software engineering research. Full citations are in NOTICE.

Metric Author(s) Year
Cyclomatic Complexity Thomas J. McCabe 1976
Cognitive Complexity G. Ann Campbell (SonarSource) 2018
CBO, DIT, NOC, WMC Shyam R. Chidamber and Chris F. Kemerer 1994
Instability, Abstractness, D' Robert C. Martin 1994, 2002
Hotspot analysis Adam Tornhill 2015
Dependency cycle detection Robert E. Tarjan 1972

These are mathematical formulas computed from source code structure. slop implements them independently via tree-sitter AST traversal. No code from the original authors' implementations is used.

License

Apache 2.0. See LICENSE.

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

agent_slop_lint-0.5.0.tar.gz (90.7 kB view details)

Uploaded Source

Built Distribution

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

agent_slop_lint-0.5.0-py3-none-any.whl (104.1 kB view details)

Uploaded Python 3

File details

Details for the file agent_slop_lint-0.5.0.tar.gz.

File metadata

  • Download URL: agent_slop_lint-0.5.0.tar.gz
  • Upload date:
  • Size: 90.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for agent_slop_lint-0.5.0.tar.gz
Algorithm Hash digest
SHA256 541346105d94182676251012f576b2ac8b8919b9061eb7ea8bd75623d92b7e40
MD5 7af169c7df5b2353602b7bc7e12ad1d5
BLAKE2b-256 34d98892639707f70271b74f9cc1c31591bdbe721ac62af1bb03ed8ec19fe7f8

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_slop_lint-0.5.0.tar.gz:

Publisher: publish.yml on JordanGunn/agent-slop-lint

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

File details

Details for the file agent_slop_lint-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: agent_slop_lint-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 104.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for agent_slop_lint-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 479d36b8fd5a7d75081f7ddc825f9c2dd852f1236e22fc800d1c4d0be4dfb788
MD5 22af3dd9d1846abe81eed67866bb2908
BLAKE2b-256 12ea35cb757e259c5c29f99caeeffb666606b545807d6e0d4ebb18948b0db0ab

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_slop_lint-0.5.0-py3-none-any.whl:

Publisher: publish.yml on JordanGunn/agent-slop-lint

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