treepeat
Find duplicate and near-duplicate code with tree-sitter
TLDR
SYNOPSIS
treepeat [-l level] [-r ruleset] commandtreepeat detect [-s percent] [--min-lines n] [-f format] [-o file] [--diff] [--fail] pathtreepeat list-ruleset [-l language] rulesettreepeat treesitter [-t] file
DESCRIPTION
treepeat scans source code for duplicate and near-duplicate regions. It parses files with tree-sitter, extracts language-meaningful regions such as functions and classes, normalizes those trees, and groups regions that meet a similarity threshold. It is a code-clone finder, not a line-oriented diff.Three built-in rulesets control normalization. none compares raw syntax trees. default (the usual setting) drops whitespace, string contents, and some high-level nodes such as names, so near-copies still match. loose also anonymizes identifiers and constants, so the same structure with different names still matches. Pass --ruleset before the subcommand.detect walks a file or directory. Matches shorter than --min-lines (default 5) are dropped. --similarity is a percent from 5 to 100; the default of 100 means the normalized trees must match exactly. Console output lists groups and a summary. --format sarif writes a SARIF report instead, which is the form most CI security dashboards ingest.Paths are skipped when they match --ignore globs or a gitignore-style file whose name matches `.*ignore` (including .gitignore). --add-regions and --exclude-regions change which syntax-node types count as a region, per language, using the form `language:node1,node2`.list-ruleset prints the rules in none, default, or loose. treesitter prints one file beside the tokens treepeat will compare, or beside the transformed source with --transformed.Supported languages include Astro, Bash, CSS, Go, HTML, Java, JavaScript, JSX, Kotlin, Lua, Markdown, Python, Rust, SQL, TSX, TypeScript, and YAML. JSX is parsed with the JavaScript grammar.The tool requires Python 3.11 or newer. Install it with `pip install treepeat`.
PARAMETERS
detect path
Scan a file or directory for similar regions.list-ruleset ruleset
Print rules for none, default, or loose.treesitter file
Show one file next to its normalized tree-sitter view.-r ruleset, --ruleset ruleset
Normalization profile: none, default, or loose. Default is default. Set this on the main command, before the subcommand.-l level, --log-level level
Log level: DEBUG, INFO, WARNING, ERROR, or CRITICAL. Default is WARNING. On list-ruleset, -l is the language filter instead.-s percent, --similarity percent
Minimum similarity, from 5 to 100. Default is 100.--min-lines n
Ignore regions shorter than n lines. Default is 5.-f format, --format format
console (default) or sarif.-o file, --output file
Write the report to file. Default is standard output. SARIF uses this path; console output is printed directly.--diff
In console output, show a side-by-side diff of the first two regions in each group.--fail
Exit with status 1 when any similar group is reported.-i globs, --ignore globs
Comma-separated globs to skip, for example `*.test.py,/node_modules/`.--ignore-files globs
Comma-separated globs that locate ignore files. Default is `**/.*ignore`.--add-regions spec
Extra region node types, as `language:node1,node2`. Repeatable.--exclude-regions spec
Region labels to drop, as `language:label1,label2`. Repeatable.--ignore-node-types types
Comma-separated AST node types to skip while extracting regions.-v, --verbose
After a console run, print timing and which node types were used.-p, --progress
Progress bars on standard error while a long scan runs.-l language, --language language
On list-ruleset only: show rules that apply to one language.-t, --transformed
On treesitter: show rewritten source on the right instead of tokens.--version
Print the version and exit.
CAVEATS
The project is a proof of concept. Language coverage is limited, and two files in an unsupported language are simply not compared.--ruleset and --log-level belong on the main command (`treepeat --ruleset loose detect …`). list-ruleset reuses -l for a language name, so a log level has to be set before that subcommand.--similarity rejects values below 5, even though some examples elsewhere say the range starts at 1. --diff and --verbose affect console output only. --fail exits 1 for any reported group, which is easy to trip on a large tree at the default ruleset. If detect cannot parse any file, it exits 1 before printing groups.
HISTORY
treepeat was written by Dane Summers and first published on PyPI in November 2025. It is released under the Apache-2.0 license.
