Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

User Guide

This guide covers installing Reforge, running scans, choosing output formats, tuning thresholds, and troubleshooting common problems.

Reforge reports maintainability and refactoring signals. It does not produce a quality score, health score, bug probability, or proof that code is safe to change.

Installation

Reforge requires Rust 1.85 or newer.

Tagged releases publish platform archives on the GitHub Releases page. When a release is available, extract its archive, then move reforge or reforge.exe to a directory on PATH. The Windows archive is a ZIP; Linux and macOS archives are compressed tar files. Each archive also contains the README and license.

Build a debug binary from this checkout:

cargo build

Build an optimized binary:

cargo build --release

Install the CLI from this checkout:

cargo install --path .
reforge scan D:\path\to\project

During local development, the examples below use cargo run -- scan .... After installation, replace cargo run -- scan with reforge scan.

Agent Skill Installation

Reforge ships an optional agent skill in skills/reforge-scan. Install it when you want an agent to run Reforge, choose report formats, interpret findings, or turn scan output into scoped refactoring recommendations.

For Codex on Windows:

.\scripts\install-agent-skill.ps1

For Codex on macOS or Linux:

sh scripts/install-agent-skill.sh

To update an existing install, pass -Force or --force:

.\scripts\install-agent-skill.ps1 -Force
sh scripts/install-agent-skill.sh --force

For another agent that consumes the same skill folder shape, pass the directory that contains skill folders:

.\scripts\install-agent-skill.ps1 -Agent generic -SkillsDir D:\path\to\agent\skills -Force
sh scripts/install-agent-skill.sh --agent generic --skills-dir ~/.agent/skills --force

The install scripts copy only the skill folder. Add -InstallCli or --install-cli to also run cargo install --path ..

Quick Start

Scan the current repository:

cargo run -- scan .

Produce stable machine-readable output:

cargo run -- scan . --output json --progress never

Disable git churn when you want deterministic static-only output:

cargo run -- scan . --churn off --hotspot-model static --output json --progress never

Write a report to disk:

cargo run -- scan . --output-file reforge-report.json --progress never

When --output is omitted, --output-file extensions .html, .htm, .json, .yaml, .yml, and .sarif select HTML, JSON, YAML, or SARIF automatically. Other extensions default to human output. Missing parent directories in the output path are created automatically, so a path such as reports/current/reforge-report.html does not need to exist before the scan.

What Gets Scanned

The scanner accepts either a directory or a single file as [PATH]. It scans source files with these extensions:

  • Broad source-file discovery: c, cc, cpp, cs, go, java, js, jsx, kt, php, py, rb, rs, ts, and tsx.
  • Tree-sitter structural analysis: Rust, JavaScript, TypeScript/TSX, Python, Go, Java, C#, Kotlin, PHP, and Ruby.

By default, hidden files are skipped and common generated or dependency directories are skipped, including target, node_modules, dist, build, out, coverage, .next, .nuxt, .svelte-kit, and .vite. Git ignore rules are also applied by default, including .gitignore, .git/info/exclude, and global git ignore files.

Use --include-hidden to include hidden paths and --include-generated to include generated or dependency directories. Use --ignore-path <PATH> to add Reforge-specific ignored paths, and use --no-gitignore to scan paths ignored by git.

Test files and test directories such as tests, __tests__, spec, and *.test.ts are scanned by default. Use --exclude-tests when you want a production-source-only scan.

Use finding filters when you want the report and CI gate to consider only part of the final scored finding set:

cargo run -- scan . --only large_file,complex_function --min-priority 35
cargo run -- scan . --exclude-detector debt_marker --severity warning

--severity warning keeps warning and critical findings. --severity critical keeps only critical findings.

Output

Reforge supports human, html, json, yaml, and sarif output.

Human output is intended for terminal review:

cargo run -- scan . --output human --progress never

JSON and YAML are intended for CI, automation, and agent-to-agent handoff:

cargo run -- scan . --output json --progress never
cargo run -- scan . --output yaml --output-file reforge-report.yaml --progress never

SARIF output targets SARIF 2.1.0 for CI code-scanning integrations:

cargo run -- scan . --output sarif --output-file reforge-report.sarif --progress never

HTML output is a React-powered visual report for local review. It is still written as a single offline HTML artifact, so it can be opened directly in a browser without a server:

cargo run -- scan . --output html --output-file reforge-report.html --progress never

Use --progress never for stable stdout. Progress is written to stderr when enabled. Use --color always, --color never, or the default --color auto to control ANSI color in human output.

Reading Results

Human output is organized for quick terminal triage:

  • Result: total threshold signals, severity counts, hotspot watchlist size, suppression summary when present, and similar-function group count.
  • Scan details: source files, directories, and function candidates scanned.
  • Signal mix: finding counts by detector kind, shown when findings exist.
  • Findings: actionable threshold signals sorted by priority.
  • Watchlist: hotspot locations ranked by static risk, churn risk, or both.

HTML output renders the same report through the React + TypeScript report app as summary cards, a severity distribution bar, construct/mechanism metadata, the File Overview, hotspot watchlist, similar-function groups, and prioritized findings. When --output is omitted, .html and .htm output-file extensions select the same HTML report format automatically.

Reports contain four main data layers plus suppression audit context:

  • raw_metrics: directory, file, function, type, and churn measurements.
  • metrics_summary: percentile summaries for the scanned project.
  • hotspots: file, function, and type locations ranked by static risk, churn risk, or both.
  • suppression_summary: counts of findings removed by suppressions.
  • issues: compatible atomic evidence grouped into refactoring issues.
  • detector_manifest: detector coverage, classification, and overlap metadata.
  • findings: actionable refactoring signals derived from thresholds and detectors.

Severity comes from priority: info is below 35, warning is 35 through 69, and critical is 70 or above. Priority is a refactoring priority signal, not a claim that the code is defective.

findings=0 means no findings remain after scoring, filters, and suppressions. It does not prove code quality, rule out bugs, or mean the hotspot watchlist and raw metrics are empty. When suppressions are used, keep the suppression summary visible so reviewers can distinguish zero unsuppressed findings from zero observed signals.

Every finding in JSON and YAML has a stable evidence id with an rf3- prefix. The ID is derived from the finding kind, primary location, related locations, and metric names so it can be used for baseline comparison.

Filtering and suppression happen after scoring, so priority, severity, and stable IDs are calculated the same way whether or not a finding appears in the final report.

unused_function findings are conservative dead-code prompts. Reforge reports private named free functions only when no same-name reference appears outside the function body. Public/exported functions, methods, and common entry-point names are skipped.

Churn and Hotspots

The default --churn auto mode collects git churn when the scan root is inside a git repository. Outside git history, auto records the reason and continues without churn. Use --churn on when git churn is required and the scan should fail if it is unavailable. Use --churn off to skip git entirely.

Hotspot models:

  • --hotspot-model static: rank by the strongest 0-100 structural risk for each location. File risk considers lines, imports, public items, and file-LOC percentile; function risk considers lines, complexity, nesting, parameters, and function-LOC percentile; type risk considers lines, members, and type-LOC percentile.
  • --hotspot-model churn: rank by the strongest 0-100 project-percentile signal from commits touched and recent weighted churn, with author-count percentile weighted at 70%. Function and type locations inherit file churn only when their static risk is at least 35.
  • --hotspot-model hybrid: default ranking, combining static_risk * 0.65 and churn_risk * 0.35, then rounding priority to an integer.

Tune churn collection with --churn-window-days and --churn-max-commit-lines. Commits above the max added+deleted line count are ignored so large mechanical changes do not dominate results.

Hotspots are a watchlist, not findings. Use them to choose where to inspect or plan refactoring work; do not treat hotspot presence alone as a hard CI gate.

CI Gates and Baselines

Use --fail-on info|warning|critical to make a scan exit nonzero when selected findings meet or exceed that severity. Reforge writes the requested report before returning the failing exit status.

CI gates evaluate selected findings only. They do not fail on raw metrics, metric summaries, or hotspot watchlist entries by themselves. Suppressed findings are excluded from gate selection, so suppression summary context matters when a blocking gate reports zero findings.

Without --baseline, all current findings are selected:

cargo run -- scan . --output json --progress never --fail-on warning

With --baseline <PATH>, Reforge reads a prior schema 18 JSON or YAML report and matches findings by stable id. Older reports without IDs are rejected; regenerate the baseline with the current Reforge.

--baseline-mode controls the selected findings:

  • new: IDs absent from the baseline.
  • new-or-worse: new findings plus findings whose priority or severity increased. This is the default.
  • all: all current findings.
cargo run -- scan . --baseline baseline.json --baseline-mode new-or-worse --fail-on warning --output json --progress never

Human reports include baseline diff counts when --baseline is supplied: new, worse, same, and resolved. Use --show new|new-or-worse|all to choose which current findings appear in the human Findings section. The default is all, so existing report output is unchanged unless the display filter is selected.

cargo run -- scan . --baseline baseline.json --show new-or-worse --output human --progress never

Before making a gate blocking, calibrate it on several real projects. Run the same JSON settings across representative repositories, compare high-priority findings with maintainers’ refactoring backlog, tune thresholds only for repeatable noise or blind spots, and validate the settings on a holdout project. Prefer --baseline-mode new-or-worse for pull request gates so unchanged legacy findings stay visible without blocking every change.

CLI Reference

Usage:

reforge init [PATH] [--force]
reforge config validate [PATH] [--config CONFIG]
reforge config show [PATH] [--config CONFIG] [--output human|json|yaml]
reforge scan [OPTIONS] [PATH]

init writes a default reforge.toml. config validate and config show parse discovered or explicit config without scanning source files or reading git churn.

OptionDefaultPurpose
--presetbalancedUse strict, balanced, or relaxed threshold defaults before per-threshold overrides.
--max-file-lines800Report files above this total line count.
--max-dir-files40Report directories above this direct source-file count.
--include-hiddenfalseInclude hidden files and directories.
--include-generatedfalseInclude dependency and generated output directories.
--no-gitignorefalseDo not apply git ignore rules during scanning.
--exclude-testsfalseExclude test files and test directories from scanning.
--ignore-pathnoneAdditional path to skip; can be repeated.
--onlynoneReport only these finding kinds, as kind[,kind...].
--exclude-detectornoneExclude these finding kinds, as kind[,kind...].
--min-prioritynoneReport findings whose final priority is at least this 0-100 value.
--severitynoneReport findings at or above info, warning, or critical.
--min-similar-functions3Report similar-function groups at or above this size.
--min-function-tokens80Ignore smaller normalized function bodies.
--function-similarity0.85Minimum normalized token similarity for grouping.
--include-test-similarityfalseInclude tests in similar-function analysis.
--max-function-lines80Report functions above this line span.
--max-function-complexity15Report functions above this estimated complexity.
--max-nesting-depth4Report functions above this nested control-flow depth.
--max-function-parameters5Report functions with more parameters than this threshold.
--max-type-lines250Report types above this line span.
--max-type-members30Report types above this member count.
--max-imports35Report files with more imports than this threshold.
--max-public-items30Report files with more public/exported items than this threshold.
--max-functions-per-file40Report over-splitting risk only when this function count and density signals are exceeded.
--max-functions-per-100-lines12Report over-splitting risk only when function density also exceeds this threshold.
--max-small-function-ratio70Report over-splitting risk only when this percentage of functions are small and simple.
--min-repeated-literal-occurrences12Report repeated literals seen at least this many times.
--min-data-clump-occurrences4Report repeated parameter groups seen at least this many times.
--include-test-structurefalseInclude tests in general structural checks.
--configdiscoveredRead a specific configuration file.
--baselinenoneRead a prior schema 18 JSON/YAML report for gate comparison.
--baseline-modenew-or-worseGate on new, new-or-worse, or all findings when a baseline is present.
--showallDisplay new, new-or-worse, or all current findings in human baseline reports.
--fail-onnoneExit nonzero when selected findings meet info, warning, or critical.
--churnautoUse auto, on, or off for git churn metrics.
--hotspot-modelhybridUse static, churn, or hybrid hotspot ranking.
--churn-window-days180Days of git history to include.
--churn-max-commit-lines2000Skip commits above this added+deleted line count.
--outputinferredUse human, html, json, yaml, or sarif.
--output-filestdoutWrite the report to a file.
--progressautoUse auto, always, or never for progress output.
--colorautoUse auto, always, or never for human-output color.
--helpnonePrint generated help.

Examples

Scan another project with stricter size thresholds:

cargo run -- scan D:\path\to\project --max-file-lines 600 --max-function-lines 60

Use a built-in threshold preset:

cargo run -- scan . --preset strict

Tune similar-function detection:

cargo run -- scan . --min-similar-functions 4 --min-function-tokens 60 --function-similarity 0.90

Include tests in duplication or structural analysis:

cargo run -- scan . --include-test-similarity
cargo run -- scan . --include-test-structure

Exclude tests entirely:

cargo run -- scan . --exclude-tests

Use a specific configuration file:

cargo run -- scan . --config reforge.toml --output json --progress never

Suppress a known intentional finding inline:

#![allow(unused)]
fn main() {
// TODO: generated migration marker reforge:ignore debt_marker tracked in issue 123
// reforge:ignore-next-line large_file generated fixture snapshot
}

Troubleshooting

failed to resolve path: confirm [PATH] exists. Put options before or after the path normally, but do not pass -- --help after scan; use cargo run -- scan --help.

scan root is not inside a git repository: use --churn off, or keep --churn auto if churn is optional. Use --churn on only when git history is required.

Unexpected generated files in results: check whether --include-generated was used and whether ignore-paths in reforge.toml should include local output directories. If a path is ignored by git and you still want to scan it, add --no-gitignore.

No similar functions found: lower --min-function-tokens, lower --function-similarity, or add --include-test-similarity if test code is in scope.

JSON output is mixed with progress text: add --progress never. Progress is intended for terminals, not machine parsing.