An agent harness that turns vibe-coded slop
into engineer-grade beautiful code
pip install desloppify — 2,500+ stars — 29 languages — 1,600+ files
github.com/peteromallet/desloppify
What is desloppify, and why should anyone care?
When you ask an AI to build something, it works fast — but it cuts corners you can't see.
Think of it as a personal code quality coach that your AI coding agent uses while it works.
Looks at every file and finds problems — dead code, duplicated logic, confusing names, security issues, untested functions.
Gives your codebase a single number (0–100). A score above 98 means "a senior engineer would call this beautiful."
Tells your agent exactly what to fix next. Fix it, mark it done, ask for the next thing. Repeat until the score is high.
You paste one prompt. The agent does the rest.
# You paste this into your AI coding agent: "I want you to improve the quality of this codebase." "Install and run desloppify." # The agent runs: pip install desloppify desloppify scan --path . # find all the problems desloppify next # what should I fix first? # Agent fixes the issue, then: desloppify resolve <id> # mark it done desloppify next # what's next? # ...repeat until the score hits your target
Most code quality tools let you cheat. Suppress a warning, score goes up. Desloppify is different.
Architecture, scoring model, detectors, review pipeline, and anti-gaming
Pure Python (3.11+), MIT licensed, installable via pip install desloppify[full]. Zero required dependencies — optional extras for tree-sitter, Pillow, bandit, PyYAML.
The codebase is organized into clean architectural layers with strict dependency boundaries.
| Layer | Package | Responsibility |
|---|---|---|
| app/ | desloppify/app/ | CLI parser, command handlers, output rendering. Thin orchestrators only. |
| engine/ | desloppify/engine/ | Detectors, scoring, state management, work queue, plan operations. |
| intelligence/ | desloppify/intelligence/ | LLM review pipeline, dimension prompts, holistic context, narratives. |
| languages/ | desloppify/languages/ | Language plugins — per-language detectors, fixers, review data, tree-sitter specs. |
Plus base/ for shared primitives (config, discovery, registry, search, text utilities) and data/ for global configuration data.
Desloppify defines a strict five-phase lifecycle. Work progresses in order:
The CLI is built on argparse with allow_abbrev=False to prevent ambiguous option shortcuts.
| scan | Run all detectors |
| status | Show current score + state |
| next | Get next fix from queue |
| backlog | View full issue backlog |
| plan | Manage execution plan |
| show | Inspect specific issues |
| tree | File structure view |
| viz | Visualizations |
| detect | Run single detector |
| autofix | Auto-apply safe fixes |
| suppress | Mark false positives |
| resolve | Mark issue as fixed |
| review | Trigger LLM review |
| move | File reorganization |
| config | Settings management |
| update-skill | Install agent guide |
| langs | Language support info |
| exclude | Path exclusions |
The engine/detectors/ package contains 15+ detectors that find issues machines can identify with certainty.
| Detector | What it finds |
|---|---|
| dupes | Duplicated code blocks (15K-line implementation) |
| orphaned | Dead / unreachable code |
| complexity | High cyclomatic complexity |
| coupling | Excessive module coupling |
| gods | God classes / objects |
| large | Oversized files |
| naming | Poor naming conventions |
| single_use | Single-use abstractions |
| Detector | What it finds |
|---|---|
| flat_dirs | Flat directory structure issues |
| coverage | Import/dependency coverage gaps |
| test_coverage | Missing test coverage |
| security | Security pattern violations |
| signature | Function signature problems |
| passthrough | Passthrough wrappers |
| graph | Dependency graph analysis |
| review_coverage | Review completeness gaps |
Each detector produces structured FunctionInfo / ClassInfo / ComplexitySignal objects with file, line, body, hash, and metrics.
29 languages supported through a layered plugin framework in languages/.
Custom detectors, fixers, review data, and tree-sitter specs:
Generic linter + tree-sitter analysis:
languages/ _framework/ # shared base base/ # abstract classes treesitter/ # tree-sitter parsing review_data/ # dimension JSONs registry/ # plugin registration typescript/ detectors/ # TS-specific detectors deps/ # dependency analysis patterns/ # pattern matching react/ # React-specific security/ # TS security rules smells/ # code smell detection fixers/ # auto-fix logic review_data/ # TS review dimensions syntax/ # syntax parsing python/ detectors/ # Python-specific fixers/ review_data/
A single number (0–100) that correlates with genuine codebase quality. The scoring formula uses dimension-weighted aggregation.
For each dimension with n detectors:
# Per dimension: total_checks = sum(detector.potential) weighted_fails = sum(detector.weighted_failures) dim_score = ( (total_checks - weighted_fails) / total_checks ) * 100 # Overall: score = weighted_average(dim_scores, dim_weights)
Three modes computed simultaneously: lenient strict verified_strict
Each scan produces six metrics:
The scoring deliberately weights subjective review 3x heavier than mechanical detection.
| Dimension | Focus |
|---|---|
| File Health | File size, structure, organization |
| Code Quality | Complexity, coupling, dead code |
| Duplication | Copy-paste detection |
| Test Health | Coverage gaps, test quality |
| Security | Pattern-based vulnerability scan |
| Dimension | Weight |
|---|---|
| High Elegance | 22.0 — architectural quality |
| Mid Elegance | 22.0 — module-level design |
| Contracts & Type Safety | Moderate |
| Design Coherence | Moderate |
| Naming Quality | Low (nudge) |
| AI-Generated Debt | Low (nudge) |
The intelligence/ package handles subjective code review via structured LLM prompts.
intelligence/
review/
dimensions/ # what to review
data.py # JSON loader + cache
holistic.py # loads dimensions
lang.py # per-lang overrides
_context/ # what to show the LLM
_prepare/ # prompt assembly
context_holistic/
budget/ # token budgeting
clusters/ # issue clustering
selection/ # file selection
context_signals/ # mechanical evidence
importing/ # score importing
narrative/ # progress stories
The difference between a useful signal and a vanity metric. Desloppify's scoring resists every obvious gaming strategy.
| Strategy | Counter-measure |
|---|---|
| Suppress warnings | "Won't fix" items widen the lenient/strict score gap |
| Hit exact targets | matches_target_score() flags scores within 5% of targets as suspicious |
| Avoid re-review | Re-reviews can lower scores if the LLM finds new issues |
| Game mechanical only | Mechanical is only 25% of the score |
| Skip attestation | Attestation requirements verify fixes were real |
The gap between lenient and strict scores is itself a meaningful signal. A large gap means lots of swept-under-the-rug issues.
All state lives in .desloppify/ so progress survives across agent sessions.
engine/_plan/ operations/ # queue manipulations policy/ # ordering rules schema/ # plan data models sync/ # state synchronization triage/ # 6-stage triage pipeline
Triage has six substages that the agent works through:
The most important command. It drives the entire execution cycle.
# Internal flow of `desloppify next`: _build_and_render_queue_view() | +-- parse options +-- check guardrails +-- load execution plan +-- _resolve_queue_items() +-- apply cluster filtering | +-- if empty: | _render_empty_queue_view() | display score context | show plan information | +-- else: _render_terminal_queue_view() render items + nudges compute narratives emit resolve command
A structured output containing:
Desloppify installs a SKILL.md workflow guide tailored to each agent platform.
| Agent | Skill file |
|---|---|
| Claude Code | CLAUDE.md |
| Cursor | CURSOR.md |
| Codex | CODEX.md |
| Copilot | COPILOT.md |
| Droid | DROID.md |
| Windsurf | WINDSURF.md |
| Gemini | GEMINI.md |
# Install the full workflow guide: desloppify update-skill claude # This writes a CLAUDE.md file that # teaches the agent the full workflow: # - When to scan vs. rescan # - How to interpret scores # - The next/resolve loop # - Triage substages # - Anti-gaming awareness
Two powerful remediation tools beyond the manual fix loop.
Safe, mechanical fixes the tool can apply directly:
app/commands/autofix/ apply_flow.py # forward fix pipeline apply_retro.py # retroactive fixes fixer_selection.py # choose right fixer preview.py # dry-run preview
Structural reorganization of files and modules:
app/commands/move/ planning.py # plan the restructure directory.py # directory-level moves language.py # language-aware moves apply.py # execute the plan reporting.py # report what changed
Visual output for tracking progress and displaying quality publicly.
app/output/
scorecard_parts/
# Left panel: score visualization
# Right panel: dimension breakdown
# Projection: future estimate
# Drawing primitives
# Badge for your README:
# Shows your current desloppify score
# as a visual badge
Desloppify dogfoods its own methodology with extensive testing.
tests/ base/ # base utility tests commands/ # CLI command tests core/ # engine core tests detectors/ # detector unit tests engine/ # engine integration intelligence/ # review pipeline tests lang/ # per-language tests narrative/ # narrative tests plan/ # plan system tests review/ # review tests (deep) scan/ # scan workflow tests scoring/ # scoring formula tests state/ # state persistence tests workflows/ # end-to-end workflows snapshots/ # snapshot testing
Core package has zero required dependencies. Tree-sitter, Pillow, bandit, and PyYAML are all optional extras. This minimizes install friction for agents.
CLI output, state format, and skill files are all optimized for LLM consumption. The dev philosophy explicitly states the human is the secondary user.
The team changes implementations freely when improvements emerge. No backward compatibility guarantees — the tool evolves fast.
Command files in app/commands/ are thin orchestrators. Business logic lives in engine/ and intelligence/.
Language plugins use dynamic imports, but only at defined registration boundaries. No hidden dynamic imports elsewhere.
Snapshot tests and extensive test suites ensure the aggressive refactoring pace doesn't break behavior.
The philosophical shift this tool embodies.
"Gets things built fast. But the codebases it produces tend to rot in ways that are hard to see and harder to fix — not just the mechanical stuff like dead imports, but the structural kind. Abstractions that made sense at first stop making sense."
"An agent with the right framework can hold a codebase to a real standard, the kind that used to require a senior engineer paying close attention over months."
"The hope is that anyone can use this to build something a seasoned engineer would look at and respect. That's the bar we're aiming for."
pip install desloppify[full] • github.com/peteromallet/desloppify • Discord community