Poly-crap finds the functions in a codebase that are both complex and poorly tested. It parses your source with tree-sitter, reads the coverage report your test runner already writes, and scores every function with the CRAP metric. It supports TypeScript, JavaScript, Python, Go, Rust, and Java, and it ships as one binary with no runtime dependencies.
Use it three ways:
- In a pull request, to fail the build when a changed function is too complex for its tests. See Changed functions.
- Against a baseline, to fail the build when any score gets worse. See Baselines.
- On a whole repository, to find the functions most worth testing or splitting next.
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/drew-simmons/poly-crap/releases/latest/download/poly-crap-installer.sh \
| shThe installer downloads a prebuilt release, checks its SHA-256 checksum, and
puts poly-crap in ~/.cargo/bin. To pin a version, replace
latest/download with download/v0.8.0.
With Rust 1.88 or newer:
cargo install poly-crap --lockedOr run cargo install --path . --locked from a clone. Prebuilt binaries cover
macOS and Linux, and there is no Windows build; see
Install for the targets.
-
Run your tests with coverage on. Poly-crap reads the report; it never runs tests itself. Coverage reports lists the command for each stack.
-
Run poly-crap from the repository root. It finds a report at any of the default locations on its own:
poly-crap
-
Read the table. Each row is a function over the threshold, and the last column names the lines a test never reached:
CRAP results CRAP CC Coverage Language Symbol Location Uncovered 6.0 4.0 50.0% python run ./app.py:4 6-8 1 more function not shown; adjust --min or --top to list them. 1 of 2 functions exceeds CRAP threshold 5.0. Coverage scope: 1 analyzed file, 1 coverage source file, 1 matched, 0 source-only, 0 coverage-only. -
Gate a branch. This scores only the functions the branch changed and exits
1when one is over the threshold:poly-crap --diff-base main --fail-above
CRAP(m) = complexity(m)² × (1 - coverage(m) / 100)³ + complexity(m)
complexity is the function's cyclomatic complexity and coverage is the
share of its executable lines that a test ran. At 100% coverage the score
equals the complexity, so a threshold also caps complexity. The coverage term
is cubed, so the first tests on a function pay off the most.
The default threshold is 5, which suits a small, well-tested codebase that
wants to stay that way. The metric's authors proposed 30, which catches the
worst offenders in an existing codebase first.
How the score works
explains both and how to pick one.
The full manual is at https://drew-simmons.github.io/poly-crap/:
- Coverage reports: formats, producing a report, auto-discovery, and path matching.
- Reading the output: the table, color, JSON, and SARIF.
- Gating changes: changed functions, baselines, and CI recipes.
- What gets scored: languages, functions, complexity rules, excludes, and allow lists.
- Reference: every option, the configuration file, and exit codes.
- Troubleshooting.
skills/poly-crap/SKILL.md teaches a coding agent such as Claude Code to run
poly-crap, make a coverage report, read the results, and gate a branch.
Install it with the skills CLI:
npx skills add drew-simmons/poly-crap --skill poly-crapOr copy the skills/poly-crap directory into .claude/skills/ in a project,
or into ~/.claude/skills/ for every project, and the agent picks it up.
The project uses Rust 1.88.0. Before submitting a change, run:
cargo fmt --all --check
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked --all-targets
cargo package --locked --allow-dirtyCI also runs poly-crap on itself with a threshold of 5 and fails the build
when a function is over it. CLAUDE.md describes the architecture
and the rules the code follows. Inside a checkout the
agent skill also builds and smoke-tests the
binary.
The docs site lives in docs/. Run pnpm --dir docs install once, then
pnpm --dir docs run dev to serve it locally.
See CONTRIBUTING.md for contribution guidance, SECURITY.md for vulnerability reporting, and RELEASING.md for maintainer release steps. See THIRD_PARTY_NOTICES.md for cargo-crap attribution.
MIT