Culler is a fast, precise dead-code analyzer for Python projects.
It is built in Rust, distributed as a single command-line tool, and designed to find dead Python code without turning ordinary public APIs, exports, tests, or dynamic edges into noisy findings.
culler check .Dead-code detection is easy to make loud and hard to make useful. Culler is intentionally conservative where Python is dynamic, and specific where static evidence is strong.
Culler currently reports:
- unreferenced functions and classes;
- production code unreachable from known application roots;
- unused imports;
- unused local bindings;
- unreachable statement ranges;
- unused private methods.
Findings are split by confidence. High-confidence findings are shown by default. Review findings remain available when useful, but they do not fail a default text run.
The recommended installation method for the CLI is pipx or uv tool.
pipx install culleruv tool install cullerYou can also install it into an existing Python environment:
python -m pip install cullerThe PyPI package installs the compiled culler binary. It does not expose a
Python import API yet.
Run Culler on the current project:
culler check .Emit machine-readable JSON:
culler check . --format jsonShow review-confidence findings as well as high-confidence findings:
culler check . --show-reviewExplain a specific candidate or finding:
culler explain <candidate-or-finding-id> .Exit codes are intentionally small:
| Code | Meaning |
|---|---|
0 |
Analysis completed without default-visible findings. |
1 |
Analysis completed and default-visible findings were reported. |
2 |
Input, configuration, parse, or completeness error. |
Culler reads configuration from pyproject.toml.
[tool.culler]
src = "src"
mode = "auto"
target-python = "3.12"For applications, declare production roots when you want reachability findings:
[tool.culler]
src = "src"
mode = "application"
root_coverage = "complete"
roots = ["my_app.cli:main"]For libraries, Culler treats exported and externally visible surfaces more conservatively:
[tool.culler]
src = "src"
mode = "library"Useful fields:
| Field | Purpose |
|---|---|
src |
Source root or roots to analyze. |
mode |
auto, application, or library. |
root_coverage |
partial or complete when roots are known. |
roots |
Application entry points such as pkg.cli:main. |
tests |
Test paths when they are not discoverable conventionally. |
target-python |
Python syntax/semantic target, currently 3.10 through 3.15. |
exclude |
Glob patterns to exclude from analysis. |
allow_partial |
Permit partial analysis without escalating to exit code 2. |
Text output is optimized for local development and CI logs. JSON output is intended for editors, dashboards, benchmarks, and automation.
culler check . --format jsonRule IDs are stable machine-readable identifiers:
| Rule | Finding |
|---|---|
CULL001 |
Unreferenced function. |
CULL002 |
Unreferenced class. |
CULL003 |
Root-unreachable function. |
CULL004 |
Root-unreachable class. |
CULL005 |
Unused import binding. |
CULL006 |
Unused local binding. |
CULL007 |
Unreachable statement range. |
CULL008 |
Unused private method. |
Diagnostic IDs such as CULL_P0101 describe analysis, parsing, or
configuration problems.
Culler includes a fixed benchmark corpus under benchmark/. The
corpus is artificial but intentionally realistic: multi-module services,
libraries, CLIs, workers, pipelines, plugin systems, configuration packages, and
utility-heavy AI-era projects.
The benchmark compares Culler with Vulture and deadcode across precision, recall, F1, runtime, and peak RSS where available. Results should be read as evidence for this corpus, not as a universal claim about every Python project.
Run the benchmark locally:
cargo build --release
python3 benchmark/run.py --culler target/release/culler --tools culler,vulture,deadcodeSee benchmark/README.md for methodology and scoring.
Prerequisites:
- Rust 1.82 or newer;
- Python 3.10 or newer;
uvfor packaging and benchmark helper commands.
Core checks:
cargo fmt --all --check
cargo check
cargo clippy --all-targets --all-features -- -D warnings
cargo test
python3 benchmark/test_run.py
python3 benchmark/run.py --validate-onlyBuild the PyPI package locally:
uvx maturin build --release --out dist --sdist
uvx twine check dist/*Culler is pre-1.0 software. The rule IDs are intended to be stable, but CLI,
configuration, and JSON output details may still evolve before 1.0.
Releases use reviewed release PRs and a changelog. See
CONTRIBUTING.md for commit discipline and release notes.
Culler is released under the MIT License. See LICENSE.