The live duplicate-code server for AI coding agents. Deslop is an LSP + MCP server that runs in your workspace and streams real-time clone signals to Claude Code, Cursor, Copilot, Continue, Codex — and your editor — as code is being written. Worst offenders surface inline before the duplicate lands, not in a CI report three commits later.
This is not a batch scanner. It is a long-running server with a file watcher, a debouncer, an incremental cache, and atomic state writes. Every editor surface and every MCP tool reads the same live state on every keystroke.
VS Code Marketplace install · Latest release · Docs · AGENTS.md recipe
The MCP server is the headline. It exposes the running analysis to any MCP-capable agent (Claude Code, Claude Desktop, Cursor, Continue, Codex) and lets the agent ask, mid-generation, "is something like this already in the repo?" — before a single byte of duplicated code is written.
The keystone tool is find-similar. The agent calls it before authoring a new function, helper, or test setup. If the proposed pattern already exists with high similarity, the agent reuses the canonical implementation instead of authoring a fresh copy. Prevention beats cure. Post-hoc deduplication is what every static analyzer already does — Deslop's edge is being live in the agent's inner loop.
Twelve MCP tools ship today:
| Tool | Purpose |
|---|---|
find-similar |
Prevention. Match a proposed snippet against the live corpus before the agent writes it. |
top-offenders |
Ranked worst clusters in the workspace. |
report-for-file / report-for-range |
Localised report for one file or one selection. |
cluster-by-id |
Full member list and signals for a single cluster. |
report-get / report-query |
Whole-workspace report + filtered query. |
rescan |
Force-refresh after large external changes. |
list-embedding-models / set-embedding-model |
Toggle the semantic (Type-4) pass. |
session-config |
Inspect the running server's config. |
schema-doc |
Self-describing JSON schema for the report payload. |
The MCP server reads .deslop-cache/live-report.json — atomically rewritten by the LSP after every file-watcher pass — and delegates find-similar to the LSP over a Unix-domain socket so snippet matching runs against the running corpus, not a stale cache. Every MCP response reflects the workspace as of the last keystroke.
Live means reactive. When you change code, every Deslop surface — the live bubble, the editor decorations, the Top Offenders tree, the cluster webview, the status bar, the MCP query results, the agent's view of the workspace — reflects the new state immediately. Not on the next save. Not when the editor refreshes. Not on a polling timer.
The LSP file watcher fires on every change with a 250 ms debounce and a 2 s cap. The pipeline runs incrementally — only the touched files get re-parsed. The new report is written atomically and a deslop/reportChanged notification fans out over the LSP wire and over MCP resources/updated. Editor surfaces, agent caches, and webviews observe the new report in the same microtask. A cluster that no longer exists in the source code cannot remain on screen, in a hover, in a code lens, or in an MCP response. Stale UI is a correctness bug, not a polish issue.
The CLI is the cold-cache fallback for one-shot audits and CI gates. Every other surface — LSP, MCP, VS Code extension — is reactive by construction. See SPEC §[PRINCIPLES-LIVE-IS-REACTIVE].
- MCP server (
deslop-mcp) — the agent surface. Twelve tools, all powered by the live LSP state. - LSP server (
deslop-lsp) — diagnostics, hover, code lens,textDocument/definition, virtualdeslop://documents, and customdeslop/*methods (reportGet,reportDelta,reportForFile,reportForRange,clusterById,duplicatesFindSimilar,embeddingListModels,embeddingSetModel,sessionConfig,reportSchemaDoc,virtualDocument,cpuReport). Firesdeslop/reportChanged,deslop/analysisState, anddeslop/embeddingProgressnotifications. - VS Code extension — bundles the LSP + MCP binaries; surfaces the live bubble, Top Offenders tree, focused-file view, session panel, cluster webview, status bar, hover, code lens, decorations, and a Compare action.
- CLI (
deslop) — cold-cache fallback. Same engine, emits.json,.txt,.htmlreports for CI gates and bulk audits.
Languages today: C#, Rust, Python, Dart — all tree-sitter grammars. No regex on source. Ever. TypeScript / JavaScript and Go are on the roadmap.
IDE extensions in development:
| IDE | Status |
|---|---|
| VS Code | Shipping (preferred install) |
| JetBrains (Rider first, then IntelliJ IDEA, PyCharm, WebStorm, RustRover, CLion) | Actively building — LSP plugin in clients/jetbrains/, Gradle-built, real-binary tests passing |
| Zed | Roadmap |
| Neovim | Roadmap |
Every detection algorithm in the table below is a real file, not a future plan:
| Research line | What it implements | Code |
|---|---|---|
| Tree-sitter parsing (Baxter 1998) | C# / Rust / Python / Dart AST per language | crates/deslop-core/src/lang/ |
| AST normalization | Type-2 collapse: __ident__ / __literal__ + comment/trivia drop |
lang/shared.rs |
| Merkle subtree fingerprints (Chilowicz 2009) | Bottom-up BLAKE3 over normalized AST | fingerprint.rs |
| Sibling-window extension | Type-3 recall over widths 2–8 | sibling.rs |
| MinHash + LSH (Broder 1997 / Indyk-Motwani 1998 / SourcererCC 2016) | 128-value MinHash, 32 × 4 banding over normalized k-grams | tokens.rs, lsh.rs |
| HNSW ANN over local embeddings (SSCD 2024) | instant-distance HNSW, deterministic seed, top-k cosine |
embedding/pairs.rs |
| Max/sum fusion (ensemble-LLM 2025) | clamp(structural + token_jaccard + embedding_cos, 0, 1), threshold 0.85 |
pair.rs |
| Worst-offenders ranking | clone_node_count × (cluster_size − 1) × log2(1 + spanned_bytes) |
cluster.rs |
| Live + reactive (LSP watcher → state file → MCP) | 250 ms debounce, 2 s cap, atomic state-file rewrite, IPC socket | live/, deslop-lsp/, deslop-mcp/ |
Full research → code map: docs/specs/SPEC.md §Algorithm implementation status. Site-facing version: Research Background.
The VSIX is the one install that gives you everything: the live bubble, the LSP server, the MCP server, and the deslop CLI all at once. The bundled binaries are the canonical ones — every MCP client below points at them by absolute path so you stay version-locked to the extension.
-
Grab
deslop-live-X.Y.Z-<target>.vsixfrom the latest GitHub release. -
Install it:
code --install-extension deslop-live-X.Y.Z-<target>.vsix
Or: Extensions panel →
…menu → Install from VSIX… -
Open a
.cs/.rs/.pyfile. The live bubble lights up the moment you type a duplicate. The command palette exposes Deslop: Open Report, Deslop: Open Worst Cluster, Deslop: Jump to Next Occurrence. The extension prepends its bundledbin/<platform>/to the VS Code processPATH, sodeslop,deslop-lsp, anddeslop-mcpare callable from the integrated terminal.
VSIX bundles binaries for darwin-arm64, darwin-x64, linux-x64, linux-arm64, and win32-x64.
If you just want the deslop binary on your shell PATH — no VS Code — use Homebrew or Scoop. Binaries are published through two repos:
- Homebrew tap: github.com/Nimblesite/homebrew-tap
- Scoop bucket: github.com/Nimblesite/scoop-bucket
brew install nimblesite/tap/deslop
deslop --versionscoop bucket add nimblesite https://github.com/Nimblesite/scoop-bucket
scoop install deslop
deslop --versionGrab the archive for your platform from the latest release and drop the binaries on your PATH.
Scan the current directory:
deslopScan a specific repo and write reports to a chosen prefix:
deslop ~/code/my-repo --output ~/reports/my-repo
# → my-repo.json, my-repo.txt, my-repo.htmlRe-render a previous JSON report without re-analysing:
deslop --from-report deslop-report.jsonFull flag reference: deslop --help.
deslop is diagnostic by default — it exits 0 no matter how much duplication it finds, so it never breaks a build you did not ask it to gate. Opt into a CI gate with one flag or one config key, and the process exits 3 when the repo-wide duplication percentage exceeds your ceiling.
deslop . --fail-over 5.0 # exit 3 if more than 5% of analysed LOC is duplicatedOr commit the ceiling so every run — local, CI, and agent — shares it. In .deslop.toml:
[threshold]
max_duplication_percent = 5.0--fail-over takes precedence over the config key. --fail-over 0 fails on any duplication. --no-fail-over clears the config ceiling for a single local run, so you can scan a repo without tripping its own gate. The percentage must be a finite number in [0.0, 100.0]; anything else exits 2.
| Code | Meaning |
|---|---|
0 |
Analysis succeeded and duplication was within the threshold (or no threshold was set). |
1 |
Runtime error — bad scan path, parse/I-O failure, or an unreachable required embedding provider. Never a panic. |
2 |
Usage error — unknown flag, or an out-of-range / non-finite threshold value. |
3 |
Duplication threshold breached. The full report is still written so CI can surface the offenders. |
name: deslop
on: [push, pull_request]
jobs:
duplication-gate:
runs-on: ubuntu-latest
env:
DESLOP_VERSION: "0.1.0" # pin the tool version — see the Releases page
steps:
- uses: actions/checkout@v4
- name: Install the Deslop CLI
run: |
curl -sSfL "https://github.com/Nimblesite/Deslop/releases/download/v${DESLOP_VERSION}/deslop-${DESLOP_VERSION}-linux-x64.tar.gz" | tar -xz
echo "$PWD/deslop-${DESLOP_VERSION}-linux-x64" >> "$GITHUB_PATH"
- name: Gate on duplication
run: deslop . --fail-over 5.0 # or omit --fail-over to use [threshold] in .deslop.toml
- uses: actions/upload-artifact@v4
if: always()
with:
name: deslop-report
path: deslop-report.htmlExit code 3 fails the step like any non-zero status. The if: always() upload keeps deslop-report.html even on a breach so a human can browse the offenders. macOS / Linux runners can brew install nimblesite/tap/deslop instead of downloading the archive.
Agents driving CI should read the For AI guide for the same gate plus how to parse the JSON report.
Deslop ships deslop-mcp — an MCP server exposing the live workspace analysis as twelve tools (see the table at the top of this README).
The VS Code extension bundles deslop-mcp alongside the LSP, and that bundled binary is the canonical one for every external MCP client too (Claude Code, Claude Desktop, Codex, Cursor, Continue). The MCP config snippets below use an absolute path into the unpacked VSIX so the agent runs the exact binary the extension ships — version-locked to the VSIX, no PATH drift, no stale cargo install shadowing the release.
After code --install-extension deslop-live-X.Y.Z-<target>.vsix, the binary lives at:
| Platform | Path |
|---|---|
| macOS / Linux | ~/.vscode/extensions/nimblesite.deslop-live-<VERSION>/bin/<platform>/deslop-mcp |
| Windows | %USERPROFILE%\.vscode\extensions\nimblesite.deslop-live-<VERSION>\bin\win32-x64\deslop-mcp.exe |
<platform> is one of darwin-arm64, darwin-x64, linux-x64, linux-arm64, win32-x64. <VERSION> is the installed extension version — bump it whenever you update the VSIX.
Do not use a
cargo install-built binary in your MCP config. Building Deslop from source producestarget/release/deslop-mcpfor testing only — it is not a distribution channel. The repo deliberately ships nomake install-binarytarget, andmake delete-path-binariesruns before every test target to scrub leaked PATH copies. The only "PATH-resolved" form that is supported is when the user installed the CLI viabrew install nimblesite/tap/desloporscoop install deslop— those package managers version the binary lock-step with releases.
Paste-ready snippet for your project's AGENTS.md / CLAUDE.md / .cursorrules: docs/snippets/agents-md-recipe.md. It teaches Claude Code, Cursor, Copilot, Continue, and Codex to check for prior art before writing new code.
claude mcp add deslop -s user -- \
~/.vscode/extensions/nimblesite.deslop-live-<VERSION>/bin/darwin-arm64/deslop-mcp \
--root .Or edit ~/.claude.json directly:
{
"mcpServers": {
"deslop": {
"command": "/Users/you/.vscode/extensions/nimblesite.deslop-live-<VERSION>/bin/darwin-arm64/deslop-mcp",
"args": ["--root", "."]
}
}
}Homebrew/Scoop CLI users may substitute "command": "deslop-mcp" (PATH lookup) since the package manager guarantees the binary version matches the install.
Edit claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"deslop": {
"command": "/Users/you/.vscode/extensions/nimblesite.deslop-live-<VERSION>/bin/darwin-arm64/deslop-mcp",
"args": ["--root", "/absolute/path/to/your/repo"]
}
}
}Restart Claude Desktop. Use an absolute path for --root — Claude Desktop doesn't inherit a working directory.
Edit ~/.codex/config.toml:
[mcp_servers.deslop]
command = "/Users/you/.vscode/extensions/nimblesite.deslop-live-<VERSION>/bin/darwin-arm64/deslop-mcp"
args = ["--root", "."]--min-nodes 30 # raise to cut noise on small clones
--no-incremental # disable the .deslop-cache/ AST cache (default: on)
--embeddings auto # opt in to semantic (Type-4) matching (default: off)
--embedding-model nomic-embed-text # any local Ollama embedding model
--embeddings defaults to off. auto probes the provider and falls back with a warning if Ollama is unreachable; required hard-fails when the provider is unreachable.
Licensed under the MIT License © NIMBLESITE PTY LTD.
Building from source
Requires Rust 1.80+ and GNU Make.
make build # release binary at target/release/deslop
make test # fail-fast tests + coverage gate
make ci # lint + test + buildSee CLAUDE.md for contributor rules and docs/specs/SPEC.md for the design spec.