A small, auditable CLI that computes per-function CRAP scores (Change Risk Anti-Patterns) from complexity + trustworthy coverage, surfaces risky functions, and emits deterministic recommendations. Primary consumers: humans doing risk assessment and agents/CI that need stable JSON + clear exit codes.
- Discover source files (by configured paths + extensions for the requested languages).
- (Optional but recommended for real CRAP) Run the user's
coverage_command(if present and not--report-only), producing a report artifact. - Parse each discovered file with the appropriate language analyzer to extract function/method ranges + cyclomatic complexity.
- Load the coverage report (if configured + present) and map line-hit data onto the exact function ranges.
- For every function that had trustworthy coverage data, compute CRAP; always compute risk + recommendations.
- Emit table (sorted by risk) or JSON; exit 2 if any measured CRAP exceeds threshold.
Warnings are collected throughout and always emitted (to stderr + in JSON warnings); they are informational.
crap4code [global-options] <command> [command-options]
Global:
-h/--help-V/--version--config <path>(default:.crap4code.tomlnext to cwd or walk up)
Commands:
init [--force] [--config <path>]scan [paths...] [--lang <lang>] [--changed] [--base-ref <git-ref>] [--format {table,json,html,compact}] [--threshold <float>] [--config <path>] [--report-only] [--baseline <prior.json>] [--function NAME] [--coverage-report PATH] [--coverage-format {lcov,coverage.py-xml}] [--limit N] [--full] [--output FILE]
Supported flags:
--lang <python|javascript|typescript|rust>(single value; default: all enabled languages)--changed(intersect discovered files with git diff vs base)--base-ref <git-ref>--format {table,json,html,compact}--threshold <float>--config <path>--report-only--baseline <prior.json>— filter output + attach deltas for exactly the functions present in a previous JSON report (the "just the parts you worked on vs baseline" workflow). See docs/user-guide/usage.md.--function NAME(repeatable) — exactfunction_namematch after analysis and coverage mapping. When the same name appears in multiple files, all matches are included; pass an explicit source path to disambiguate. Exit 1 when no match. Summaries, recommendations, threshold, and exit 2 apply only to selected rows.--coverage-report PATH— override configured report path for this scan (absolute or repo-relative). Does not mutate TOML. Missing explicit path → exit 1 (no fallback to config).--coverage-format {lcov,coverage.py-xml}— override configured format; validated against the report file when combined with--coverage-reportor when overriding format alone.--limit N— positive integer; rich table truncation only (ignored for compact).--full— show all functions in rich table.--output FILE— write report;.html/.jsoninfer format when--formatomitted.
- Python coverage input:
coverage.pyXML - JavaScript / TypeScript coverage input: LCOV
- Rust coverage input: LCOV
- Missing or unmappable coverage is
indeterminate - Indeterminate coverage never produces a fake CRAP score
- See
docs/user-guide/concepts.mdfor user-friendly explanations of coverage reports, formats, indeterminate coverage, and the mapping process.
Each function row includes:
languagefile_pathcontainerfunction_namestart_lineend_linecomplexitycoverage_percentcoverage_statecrap_scorerisk_levelrecommended_actions- (optional, only with
--baseline)baseline_crap_score,baseline_coverage_percent
Human table is risk-sorted (high risk first). Columns are stable. coverage and crap show N/A + warning when indeterminate.
One plain line per function (no Rich, summary, recommendations, or ANSI on stdout):
file::function | lines=START-END | CX=N | coverage=N.N% | CRAP=N.NN | risk=LEVEL
Use coverage=N/A and CRAP=N/A when indeterminate. Warnings remain on stderr.
Stable top-level keys for agents:
summaryfunctions[]recommendations[]run_metadatawarnings[]
Exit codes:
- 0: success (all measured CRAP <= threshold in the filtered result set, or no measured functions)
- 1: CLI error, coverage command failed,
--functionno match, or invalid/missing explicit--coverage-report/ format mismatch - 2: one or more measured functions in the filtered result set exceeded threshold
See src/crap4code/cli.py, core/report.py, core/models.py, core/recommendations.py, core/coverage.py, and the language analyzers for the implementation.