Desloppify: an agent harness that turns scan results into a fix queue
Agent harness to make your slop code well-engineered and beautiful.
At a glance
- What is it?
- Desloppify is a Python CLI that scans a codebase for mechanical and subjective quality issues, scores them by dimension, and hands an AI coding agent an ordered queue to work through. It is opinionated about state, scoring, and what counts as done.
- Who is it for?
- Adopt Desloppify if you already run an AI coding agent against a single coherent project directory and want a persistent, scored work queue rather than a one-shot lint report. Skip it if you need diff-only incremental scanning, since the README states that true incremental or diff-only scanning is not the supported model yet.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 141 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Desloppify solves, and who it is actually for
Most linters stop at a list. You get 400 findings, you sort them yourself, and the list is stale the moment you start fixing. Desloppify's premise is different: it treats codebase quality as a persistent, scored project with an execution queue that survives across sessions. The README describes it as giving your AI coding agent "the tools to identify, understand, and systematically improve codebase quality", combining mechanical detection with LLM review and then working through a prioritized fix loop.
The target user is narrower than the tagline suggests. This is built for someone who already has an agent (Claude, Cursor, Codex, Copilot, Droid, Windsurf, Gemini or Rovodev are the skill targets named in the README) and wants that agent to work from a structured backlog instead of improvising. If you are not running an agent, the tool still scans and scores, but the loop that makes it distinctive goes unused.
There is a second audience worth naming. Desloppify's scoring is designed to resist gaming, and the README claims a score above 98 "should correlate with a codebase a seasoned engineer would call beautiful". That is a strong claim, and it is the kind of claim you should test against your own codebase before trusting it as a gate.
The scan, review, triage, execute, rescan pipeline
The README lays out a five-stage cycle: scan, score, review, triage, execute, rescan. Each stage has a distinct job, and the separation matters.
Scan runs mechanical detectors across the codebase: dead code, duplication, complexity, test coverage gaps and naming issues. Each issue is scored by dimension, with File health, Code quality and Test health given as examples. Review is where an LLM assesses dimensions that detectors cannot reach: naming, abstractions, error handling patterns, module boundaries. Those subjective scores sit alongside the mechanical ones in the same score.
Triage is the part most tools skip. The agent observes findings, reflects on patterns, organizes issues into clusters, and enriches them with implementation detail. The output is an ordered execution queue. Critically, the README states that only items explicitly queued appear in `next`; before triage, all mechanical issues are visible in the queue sorted by impact, which the README itself calls noisy.
Execute is the loop itself: `next` to see the current item, fix it, `resolve` it, run `next` again. Rescan verifies improvements and catches cascading effects. State lives in `.desloppify/`, which is why progress carries across sessions and why the README tells you to add that directory to `.gitignore`.
The gaming resistance is structural rather than a filter. Wontfix items widen the gap between lenient and strict scores, and re-reviewing a dimension can lower the score if the reviewer finds new issues. That second property is unusual: most quality scores only go up when you re-run them.
Installing Desloppify and running a first scan
The package requires Python 3.11 or newer. The README's recommended install pulls the full optional dependency set, which includes tree-sitter, bandit, Pillow, PyYAML and defusedxml. Run it with pip:
pip install --upgrade "desloppify[full]"Next, install the workflow guide for your agent. The README lists claude, cursor, codex, copilot, droid, windsurf, gemini and rovodev as the available targets:
desloppify update-skill claudeBefore scanning, the README advises checking for directories that should be excluded (vendor, build output, generated code, worktrees) and excluding the obvious ones. The `exclude` subcommand takes a path:
desloppify exclude vendor/ build/
desloppify scan --path .`--path` is the directory to scan. Use `.` for the whole project or a subdirectory such as `src/`. After the scan completes, the execution queue is read with `next`:
desloppify nextThe README describes `next` as the execution queue from the living plan, not the whole backlog. It reports what to fix now, which file, and the resolve command to run when the fix is done. `desloppify backlog` is the command for inspecting broader open work that is not currently driving execution.
Monorepos need one scan per project, not one scan of the root
This is the constraint most likely to bite a new user, and the README is explicit about it. Scanning a parent directory that contains multiple programs mixes state and path context across unrelated codebases, producing unreliable results. Each `--path` target should be a single coherent project.
For a frontend and backend in sibling directories, the README's example scans them separately and pins the language for each:
desloppify --lang typescript scan --path ./frontend
desloppify --lang python scan --path ./backendBecause state is maintained per language, a TypeScript frontend and a Python backend can coexist in the same workspace without conflict, provided you target them individually. In CI, the README repeats the advice: for monorepos, run one job or matrix entry per project path rather than scanning the workspace root.
There is a related limitation worth stating plainly. True incremental or diff-only scanning is not the supported model yet, according to the README. Desloppify in CI works best as a full-codebase health gate. If your workflow depends on scanning only changed lines in a pull request, this is the wrong tool for that job, and the README says so rather than leaving you to discover it.
Using Desloppify as a CI gate, and the Java runner caveat
The CI profile is a different shape from the interactive loop. `--profile ci` skips slow and subjective phases and bypasses the mid-cycle scan queue gate so a job can collect a fresh mechanical snapshot. `--no-badge` suppresses badge generation. The README's minimal GitHub Actions example runs both commands after installing the full extras:
name: desloppify
on:
pull_request:
push:
branches: [main]
jobs:
health:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install --upgrade "desloppify[full]"
- run: desloppify scan --path . --profile ci --no-badge
- run: desloppify status --json`status --json` is the machine-readable output a script can use to read the strict and objective scores and enforce a threshold of your own choosing. Desloppify does not ship a threshold policy; that decision stays with you.
One environment variable is documented for constrained runners. On Java CI machines, the PMD detector defaults to `--threads 0` to avoid worker-thread fanout. Setting `DESLOPPIFY_PMD_THREADS` to a value such as `2` or `0.5C` increases throughput. Note that `0.5C` is a fractional-core value, not a plain integer, so a script that validates the variable as an int will reject a legitimate setting.
Language depth varies more than the headline number suggests
The README says Desloppify currently supports 29 languages, but the support is tiered, and the tiers are not equivalent. Full plugin depth covers TypeScript, Python, C#, C++, Dart, GDScript, Go and Rust. Ruby, Java, Kotlin and 18 others get generic linter plus tree-sitter support.
That distinction should drive your evaluation. A generic linter and tree-sitter path will surface syntax-level and lint-level findings, but the deeper detectors that feed the mechanical dimensions are the ones built per language. If your stack is Ruby or Kotlin, expect a thinner scan than a Go or Rust project would get, and expect the subjective review dimensions to carry more of the score.
C++ has its own wrinkle. The README states that `compile_commands.json` is the primary analysis path, and that Makefile repositories fall back to best-effort local include scanning. Best-effort include scanning is a materially weaker signal about dependency structure than a compilation database, so a CMake project with an exported `compile_commands.json` will get more reliable results than a hand-written Makefile project.
The optional dependency groups reflect this tiering too. `treesitter`, `csharp-xml`, `python-security`, `scorecard` and `plan-yaml` are separate extras, and `full` bundles them. Installing the base package without extras leaves those detectors unavailable, which is worth knowing if your CI installs the bare package name.
How Desloppify differs from running a linter plus a review prompt
The honest alternative is what most teams already do: run ESLint, Ruff, golangci-lint or an equivalent, pipe the output into a prompt, and ask the agent to fix things. That approach has real advantages. It is stateless, it needs no new dependency, and the linter is a tool your team already understands.
The difference is what happens between runs. A linter report is regenerated from scratch every time; there is no memory of what you decided to leave alone, no queue ordering, and no way to distinguish a new regression from a finding you triaged last week. Desloppify persists state in `.desloppify/` and separates the full backlog from the execution queue, which is the mechanism that lets an agent work across multiple sessions without re-litigating settled decisions.
The scoring model is the second difference. A linter gives you counts. Desloppify gives you dimension scores plus a strict score, and the README claims the scoring resists gaming through wontfix widening and re-review that can lower scores. Whether that holds for your codebase is an empirical question. The README's own framing, that a score above 98 should correlate with a codebase a seasoned engineer would call beautiful, is a hypothesis you can falsify by scanning a project you know well and reading the result critically.
There is also a cost the alternative does not have. Desloppify introduces a state directory, a per-language state model, a triage step that gates what appears in `next`, and a CI profile that deliberately skips subjective phases. That is more moving parts than a linter invocation, and the README's own warning about pre-triage queue noise suggests the early experience is not tidy.
Maintenance, licence and what to check before adopting
The repository is not archived. The last push was on 2026-05-13, which is more than four months before today, so treat the project as one with a recent release but no evidence of continuous activity in the months since. The v1.0 release is dated 2026-05-13, the same day as the last push, following v0.9.15 on 2026-04-06 and v0.9.14 on 2026-03-24. The cadence in the months before v1.0 was roughly every two to three weeks, and then it stops at the 1.0 tag.
Upgrade cost is low on the surface. The package is pure Python with no required runtime dependencies (`dependencies = []` in pyproject.toml), so the base install is small and the optional extras are opt-in. The `full` extra pins `tree-sitter-language-pack>=0.3,<1.8`, an upper bound that will eventually need attention if the language pack moves past 1.8. The Makefile shows the project's own CI targets, including `ci`, `ci-fast`, `lint`, `typecheck`, `arch`, `ci-contracts`, `integration-roslyn`, `tests`, `tests-full`, `sync-docs` and `package-smoke`, which tells you the maintainer runs a multi-gate pipeline rather than a single test command.
The licence needs a direct look. The repository's licence field reports NOASSERTION, and pyproject.toml declares `license = {text = "OSNL-0.2"}`. OSNL-0.2 is not a licence identifier this article can interpret for you, and the classifier metadata says Production/Stable, which is a claim about maturity rather than a legal statement. Read the LICENSE file at the repository root and route it through whatever process your organisation uses for non-standard licences. Do not assume it behaves like MIT or Apache-2.0 because the package is on PyPI.
Editorial conclusion
Adopt Desloppify if you already run an AI coding agent against a single coherent project directory and want a persistent, scored work queue rather than a one-shot lint report. Skip it if you need diff-only incremental scanning, since the README states that true incremental or diff-only scanning is not the supported model yet. Before committing, verify three things: that your language has full plugin depth rather than generic tree-sitter support, that .desloppify/ is in your .gitignore, and that the OSNL-0.2 licence text in the LICENSE file matches what your organisation accepts. For C++ projects, confirm whether compile_commands.json exists, because the README treats it as the primary analysis path and falls back to best-effort local include scanning for Makefile repositories.
Frequently asked questions
What Python version does Desloppify require?
Desloppify requires Python 3.11 or newer. The README states this in the install instructions, and pyproject.toml sets requires-python to >=3.11 with classifiers for 3.11, 3.12 and 3.13.
How do I install the Desloppify skill for my coding agent?
Run desloppify update-skill followed by your agent name. The README lists claude, cursor, codex, copilot, droid, windsurf, gemini and rovodev as the available targets.
Can I scan a monorepo with Desloppify in one pass?
No. The README states that scanning a parent directory containing multiple programs mixes state and path context across unrelated codebases and produces unreliable results. Each --path target should be a single coherent project, scanned separately.
Does Desloppify support diff-only scanning in CI?
Not according to the README, which states that true incremental or diff-only scanning is not the supported model yet. It recommends using the ci profile as a full-codebase health gate and comparing full results across runs.
What licence does Desloppify use?
pyproject.toml declares license = {text = "OSNL-0.2"}, and the repository's licence field reports NOASSERTION. The LICENSE file at the repository root is the authoritative text, and the README does not explain the terms.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/peteromallet-desloppify)