Deslop Moves Flutter Duplicate Detection into the AI Agent’s Write Loop
AI coding agents produce structurally identical code under different names at scale, and Flutter’s declarative widget trees amplify the problem. Deslop shifts duplicate detection from post-commit linting to a pre-generation retrieval step, cutting the review burden before near-clones diverge and accumulate separate bug-fix histories.
AI-generated Flutter code accumulates near-identical loading branches, formatters, and repository logic because LLMs lack a global view of the codebase. Deslop attacks this by parsing Dart syntax trees with Tree-sitter, normalizing identifiers and literals, then computing Merkle hashes for exact clones and MinHash/LSH signatures for approximate clones. An optional embedding layer can catch semantically similar but syntactically different implementations.
The tool ships as a CLI, a VS Code extension with an LSP, and an MCP server that lets coding agents query the repository’s structure index before generating a new function. A fused similarity score — the max of structural match, token Jaccard, and embedding cosine — drives clustering and ranking, with a CI gate that fails the pipeline when duplication exceeds a configured threshold.
Deslop does not demand that all duplicates be eliminated. Identical AST shapes can serve different domain semantics, and Flutter projects carry legitimate repetition across platform isolates, diverging page skeletons, and independent packages. The tool supplies structural evidence; the developer still decides what to merge.
Deslop’s architecture inverts the usual static-analysis workflow: instead of scanning after code lands, it injects a retrieval step into the agent’s generation loop, making the LSP the live index and the MCP server a thin query layer over IPC.
The transitive-closure clustering is a deliberate trade-off — it increases recall at the cost of precision, meaning a cluster can contain members that are not directly similar to each other. This forces a human to inspect before extracting a shared abstraction.
The fused score uses max() rather than a weighted average, which means a pair with perfect structural match (1.0) passes the 0.85 gate even if token and embedding signals are weak — a design choice that prioritizes not missing exact clones over suppressing false positives.
Deslop explicitly down-weights structural_only matches and large data blocks to 0.15×, acknowledging that identical AST shapes with thin content (e.g., empty widget shells) are noise, not actionable duplication.
The tool’s own guidance draws a sharp line: structural similarity is evidence, not a mandate. Two functions with identical AST shapes but different domain semantics (price formatting vs. weight formatting) should stay separate, and merging them would create a fragile abstraction that breaks under future requirements.