Overview
See what deserves a refactor.
See the evidence first.
Reforge analyzes the structure of a codebase, explains every finding, and makes gaps in analysis visible.
reforge analyze . --output html --output-file reforge-report.html
From signal to decision
Reforge does not hide structural observations behind a score. It gives reviewers the context needed to decide whether a change is worthwhile.
Find the pressure points
Surface duplication, oversized responsibilities, dependency tangles, naming drift, and difficult value paths.
Inspect the evidence
Trace each finding back to its rule, measurements, source locations, and exact value-flow witness when available.
Know the limits
See partial and unsupported analysis explicitly. No findings never means more coverage than Reforge actually observed.
What Codebase looks for
Responsibilities
Find oversized files, functions, types, public surfaces, and directories that may own too much.
Duplication and drift
Inspect repeated implementations, overlapping shapes, generic buckets, naming drift, and dependency tangles.
See how Codebase analysis works →
Designed for review, not scoring
Findings are inspection prompts—not severity labels, priorities, or defect predictions. Reforge runs locally, uploads no source code, and collects no telemetry. Use it interactively, generate a standalone HTML report, or compare reviewed JSON baselines in CI. An advanced Dataflow analysis is available when exact value-path inspection is needed, but it is not required for normal Codebase use.
User guide
Install
The verified release installer chooses the supported asset for the current OS and CPU, validates it against the release SHA256SUMS, checks reforge --version, and atomically installs the binary. It also installs the reforge-analyze Codex skill unless disabled.
Unix:
curl -fsSL https://raw.githubusercontent.com/LyleMi/Reforge/main/scripts/install.sh | sh
# Pin a release or choose a destination:
curl -fsSL https://raw.githubusercontent.com/LyleMi/Reforge/main/scripts/install.sh | \
sh -s -- --version v0.2.0 --bin-dir "$HOME/.local/bin"
The Unix default is ${REFORGE_INSTALL_DIR:-$HOME/.local/bin}. Supported assets are Linux x86_64 and macOS x86_64/aarch64.
PowerShell:
$installer = Join-Path $env:TEMP "install-reforge.ps1"
irm https://raw.githubusercontent.com/LyleMi/Reforge/main/scripts/install.ps1 -OutFile $installer
& $installer
# Pin a release or choose a destination:
& $installer -Version v0.2.0 -BinDir C:\Tools\Reforge
Windows x86_64 defaults to %LOCALAPPDATA%\Reforge\bin. Use --skip-skill or -SkipSkill to install only the binary. Neither installer edits PATH; when necessary it prints the exact command to add the selected directory. Re-running an installer safely replaces the same version or upgrades it.
From a source checkout, the existing scripts/install-reforge.sh, scripts/install-reforge.ps1, and .bat wrapper remain available for cargo install --path development workflows.
Analyze
Run the default Codebase analysis:
reforge analyze . --reproducible
Dataflow is explicit. Run it alone or combine both core analyses over one workspace index:
reforge analyze . --analysis dataflow --output json --reproducible
reforge analyze . --analysis codebase --analysis dataflow --reproducible
Use --output and --output-file for human, HTML, JSON, YAML, or SARIF reports. Raw Codebase metrics and the complete Flow IR are opt-in debug sidecars:
reforge analyze . --analysis codebase --metrics-output metrics.json
reforge analyze . --analysis dataflow --flow-ir-output flow-ir.json
Read a report
Treat issues as the only decision units. Each Issue owns one typed subject and one or more Evidence records. Evidence identifies the rule and may include measurements, locations, and an ordered Dataflow witness.
Read Coverage before interpreting absence. Check the selected analysis status, every language receipt, capability limitation, rule execution, and suppression count. An empty Issue list is an observed zero only where Coverage is observable. Dataflow never represents a partial or unresolved path as exact.
Reforge intentionally emits no health score, severity, priority, or defect probability.
Baselines and CI gates
A baseline must use a compatible report format with the same producer, identity scheme, and workspace identity. Producer versions and unrelated analysis sets may differ. Coverage, scope, configuration, policy, or rule-semantic changes produce an unknown baseline state instead of claiming that an Issue is new or resolved.
After reviewing and storing a baseline report, gate new, updated, or unknown policy Issues with:
reforge analyze . --output json --output-file current.json \
--baseline reforge-baseline.json --gate new --reproducible
--gate all fails on every current policy Issue. Rules are preview/off by default; enable and enforce the selected rule IDs in versioned reforge.toml.
Configuration and rules
reforge init writes a versioned configuration. Use reforge config validate, reforge config show, and reforge rules --output json to inspect effective settings and rule contracts. Durable settings belong in reforge.toml; temporary overrides use --set key=value.
Troubleshooting
Use Coverage and its capability limitations when zero Issues are reported. Regenerate incompatible older reports rather than editing them. If a Dataflow policy is rejected, verify that it names one supported language and that every source and sink path/symbol names exactly one frontend declaration.
Configuration
reforge.toml is versioned with version = 2. Generate it with reforge init.
version = 2
[analysis]
enabled = ["codebase"]
[scope]
include-hidden = false
include-generated = false
no-gitignore = false
exclude-tests = false
ignore-paths = []
[rules]
enable = []
disable = []
enforce = []
[codebase]
preset = "balanced"
churn = "auto"
max-file-lines = 600
[dataflow.search]
max-path-steps = 24
max-function-hops = 8
max-module-hops = 8
max-paths-per-source = 100
max-sinks-per-source = 100
work-budget = 100000
[dataflow.relay]
min-function-hops = 4
min-module-hops = 2
min-relay-percent = 90
[dataflow.fan-out]
min-sinks = 4
min-modules = 3
Rule arrays require complete IDs. Duplicate, conflicting, and unknown IDs are
errors. enforce implies enable and accepts only stable rules. Experimental
rules remain internal observations; preview rules are off unless enabled and
can only produce advisory Issues. Only explicitly enforced stable rules produce
policy Issues or participate in a gate.
Each Dataflow policy is single-language and names exact sink declarations:
[[dataflow.policies]]
name = "http-client"
language = "typescript"
protected-paths = ["src/domain/**"]
adapter-paths = ["src/adapters/http/**"]
exempt-paths = ["src/bin/**"]
[[dataflow.policies.sinks]]
path = "src/transport.ts"
symbol = "send"
A policy is rejected when its language is unsupported or a sink does not match exactly one public source symbol. Adapter bypass evidence requires a complete policy and an all-exact, value-preserving witness. Search budgets limit exploration and are not smell thresholds.
The versioned file is parsed as optional typed fields. Reforge then creates one
complete effective configuration by applying built-in defaults, preset,
configuration file, --set, and CLI scope overrides in that order. reforge config show prints every effective leaf together with its source.
Codebase analysis
Codebase is Reforge’s default analysis. It reviews repository structure and produces evidence-backed findings for maintainers to inspect before deciding on a refactor.
reforge analyze .
What it examines
Codebase builds one project-wide index before applying any rule. That index contains files, directories, declared functions and types, imports, local dependencies, naming patterns, repeated syntax, test structure, and optional Git history.
Rules use that shared view to look for four broad kinds of pressure:
| Area | Typical findings | Review question |
|---|---|---|
| Responsibilities | Large files and types, long or complex functions, broad directories | Does this unit own more than one reason to change? |
| Duplication | Similar functions, repeated literals, repeated setup, overlapping type shapes | Is the repetition intentional, or is a shared concept missing? |
| Architecture | Dependency cycles and hubs, parallel implementations, boundary bypasses | Is ownership clear, and do dependencies point in the intended direction? |
| Consistency | Naming drift, generic buckets, stale compatibility paths, debt markers | Has a temporary or local convention spread beyond its original purpose? |
The complete list is in the Rule Reference.
Enable the rules you want to review
Rules start as opt-in previews. Running Codebase still records its coverage, but
a rule produces findings only after it is enabled in reforge.toml:
version = 2
[analysis]
enabled = ["codebase"]
[rules]
enable = [
"reforge.codebase.large_file",
"reforge.codebase.long_function",
"reforge.codebase.dependency_cycle",
"reforge.codebase.similar_functions",
]
[codebase]
max-file-lines = 600
max-function-lines = 80
Start with a small set whose meaning is easy to review in your repository. Adjust a threshold when the evidence is consistently too broad or too narrow; do not tune it merely to force a clean report.
Read a finding
A finding is the unit to review. It names one file, symbol, repository, or related group and contains one or more Evidence records. Evidence answers three questions:
- Which rule made the observation?
- Where in the source was it observed?
- Which measurement crossed the configured threshold?
Legitimate exceptions are expected. Generated facades, protocol signatures, composition roots, test builders, and deliberate compatibility layers can all look unusual for good reasons. Keep those decisions visible with a documented suppression instead of weakening a useful rule globally.
Check Coverage before trusting an empty result
Coverage records the files and languages seen by Codebase, the rules that ran, and any limitations. An empty findings list means only that the enabled rules found nothing within the observed surface. It does not prove that the codebase is healthy or defect-free.
Generate a report
Use the terminal output for quick review or create a standalone HTML file for a larger repository:
reforge analyze .
reforge analyze . --output html --output-file reforge-report.html
reforge analyze . --output json --output-file reforge-report.json --reproducible
JSON is the appropriate format for reviewed baselines and CI. See the User Guide for the baseline workflow and Configuration for scope, thresholds, and suppressions.
Advanced value-path analysis
Codebase is sufficient for normal structural review. Reforge also offers an opt-in Dataflow analysis for teams that need conservative, source-to-sink value paths or explicit adapter-boundary policies.
Rule cards
Every core rule is a refactoring-inspection claim, not a defect prediction, health score, generic priority, or automatic architecture inference. All cards inherit these non-goals. A finding’s identity comes from its typed subject and the rule-specific semantic anchor, not prose, ordering, checkout location, or line numbers. Measurement, threshold, evidence-set, or witness changes update the finding’s content fingerprint.
All rules below are currently preview, default_enabled = false,
validation_basis = fixture, semantic version 1.0.0, and ineligible for
enforcement. A language can become stable only through the audited calibration
protocol in calibration/README.md; other languages remain preview.
| Rule | Claim / inspection question | Capability | Positive and negative fixtures | Legitimate exceptions |
|---|---|---|---|---|
reforge.codebase.large_file | A file exceeds the configured line boundary; is responsibility ownership too broad? | file inventory | over/under threshold | generated facades, declarative tables |
reforge.codebase.large_directory | A directory owns more direct source files than configured. | directory inventory | wide/narrow directories | flat packages with explicit ownership |
reforge.codebase.debt_marker | A source comment explicitly declares TODO/FIXME debt. | source text | comment/non-comment markers | generated or externally tracked markers |
reforge.codebase.similar_functions | Multiple normalized bodies are structurally similar enough to inspect together. | parsed syntax similarity | cloned/distinct bodies | protocol implementations, tests |
reforge.codebase.long_function | A declared function exceeds the configured line span. | syntax and symbols | long/short functions | generated parsers, linear tables |
reforge.codebase.complex_function | Estimated branch complexity exceeds the configured bound. | parsed control syntax | branch-heavy/linear functions | explicit state machines |
reforge.codebase.deep_nesting | Lexical control nesting exceeds the configured bound. | parsed control syntax | nested/guard-clause fixtures | recursive walkers |
reforge.codebase.many_parameters | A function declares more parameters than configured. | symbol parameters | over/under arity | serialization and FFI boundaries |
reforge.codebase.large_type | A type exceeds configured span or member count. | type observations | large/small declarations | generated schemas |
reforge.codebase.large_public_surface | A file exports more items than configured. | export syntax | broad/narrow modules | deliberate prelude or facade |
reforge.codebase.import_heavy_file | A file imports more dependencies than configured. | import syntax | over/under import count | composition roots |
reforge.codebase.function_proliferation | A file combines high function count, density, and small-function ratio. | function inventory | dense/sparse files | parser combinators |
reforge.codebase.unused_function | A private symbol has no supported project-local reference. | symbols and references | referenced/unreferenced symbols | reflection, callbacks, macros |
reforge.codebase.repeated_literal | A literal repeats enough to inspect ownership. | parsed literals | repeated/unique literals | protocol constants and test data |
reforge.codebase.repeated_error_pattern | Error-handling syntax repeats across sites. | parsed error syntax | repeated/distinct handlers | intentionally local recovery |
reforge.codebase.test_duplication | Test setup patterns repeat across tests. | parsed test syntax | duplicated/distinct setup | readability-focused local setup |
reforge.codebase.happy_path_only_tests | A test group has assertions without detected failure/boundary cases. | test syntax | positive-only/mixed tests | behavior proven elsewhere |
reforge.codebase.file_naming_drift | A directory mixes file naming conventions. | path inventory | mixed/uniform names | language-required names |
reforge.codebase.directory_drift | Directory concepts exceed the configured ownership bound. | paths and syntax names | mixed/cohesive fixtures | plugin registries |
reforge.codebase.data_clump | The same parameter combination recurs across functions. | symbol parameters | recurring/distinct sets | stable protocol signatures |
reforge.codebase.parallel_implementation | Similarly named capabilities are implemented independently. | symbol concepts | parallel/unrelated names | platform-specific variants |
reforge.codebase.shadowed_abstraction | Local helpers overlap a shared abstraction. | symbols and concepts | local/shared overlap | deliberate compatibility shims |
reforge.codebase.duplicate_type_shape | Type field shapes substantially overlap. | type fields | overlapping/distinct shapes | boundary DTOs |
reforge.codebase.config_key_drift | Configuration-like keys repeat or drift. | literal concepts | repeated/distinct keys | external protocol keys |
reforge.codebase.fixture_factory_drift | Test fixture/factory concepts repeat independently. | test symbols | duplicated/distinct factories | domain-specific builders |
reforge.codebase.generic_bucket_drift | A generic directory or file accumulates unrelated concepts. | typed file/directory subjects | generic/cohesive buckets | intentionally tiny shared kernels |
reforge.codebase.adapter_boundary_bypass | Naming/syntax suggests direct access around an adapter. | heuristic concepts | bypass/non-bypass fixtures | migration and bootstrap code |
reforge.codebase.stale_compatibility_path | Compatibility markers lack an explicit retirement boundary. | parsed compatibility syntax | stale/owned paths | supported long-term compatibility |
reforge.codebase.dependency_cycle | Resolved project-local dependencies form a cycle. | dependency graph | cyclic/acyclic graphs | mutually recursive generated modules |
reforge.codebase.dependency_hub | A file has unusually broad/deep resolved dependency topology. | dependency graph | hub/leaf graphs | composition roots and public facades |
reforge.dataflow.adapter_flow_bypass | An exact, value-preserving path violates a complete single-language adapter policy. | exact local/interprocedural flow | exact bypass/conforming and unsupported fixtures | explicit exemptions |
reforge.dataflow.excessive_relay | An exact path contains configured forwarding depth; inspect ownership only. | exact direct-call flow | long/short relay paths | pipelines, middleware, telemetry |
reforge.dataflow.flow_fan_out | One exact source reaches many supported sinks/modules. | exact direct-call flow | fan-out/narrow paths | orchestrators and event distribution |
Similarity, literal, generic-bucket, unused-function, adapter, relay, and fan-out heuristics remain preview/off until each language independently meets the calibration gates. Self-scan is regression data only and cannot promote a rule or select a threshold.
Dataflow
Dataflow builds a language-neutral Flow IR for Rust, JavaScript/TypeScript/TSX, and Python. Selecting Dataflow records internal observations and capability receipts; enabled preview rules can surface advisories, while configured policies add exact bypass evaluation.
Coverage retains every language discovered in the shared workspace index.
Rust, JavaScript, TypeScript, TSX, and Python receive rule observations;
other languages are explicitly unsupported. Parse failures, unresolved
edges, path truncation, and missing policy configuration use stable
language/rule limitation codes and explicit capability receipts.
Preview rules
reforge.dataflow.excessive_relay, when enabled, requires an exact complete path meeting all three inclusive relay minima: function hops, module hops, and relay percent.reforge.dataflow.flow_fan_out, when enabled, groups by source symbol and requires both the distinct sink-symbol and module minima.reforge.dataflow.adapter_flow_bypass, when enabled, requires an explicit policy and an exact complete witness that bypasses its adapter.
All three are preview, default off, and advisory-only. Same-module
forwarding, modeled or unresolved paths, unsupported semantics, generated or
test sources, and truncated searches do not produce these Issues.
Search and signal thresholds
Search budgets bound deterministic traversal under [dataflow.search]:
max-path-steps, max-function-hops, max-module-hops,
max-paths-per-source, max-sinks-per-source, and work-budget.
Signal thresholds live separately under [dataflow.relay] and
[dataflow.fan-out]. Changing a search budget never changes the rule claim.
Treat zero Issues together with coverage. partial, unsupported, and stable
limitation codes identify where absence is not evidence.
Measurements and evidence
Measurements are typed values attached to Evidence. Each records a stable name, numeric value, optional numeric threshold, and unit. Evidence adds a rule, message, locations, and an optional typed Dataflow witness.
A measurement is evidence for a detector decision, not a quality score. Reforge does not combine measurements into grades, normalized health scores, or cross-rule rankings.
Issues are the baseline, gate, and SARIF decision unit. Evidence explains why an Issue exists. Prose and ordering do not change identity; measurements, thresholds, evidence-set changes, and substantive witnesses update the content fingerprint while the same typed subject keeps its Issue ID.
Coverage records the observed denominator, rule activation and maturity, and language capability limitations. An unsupported or unresolved semantic surface is never inferred as an exact edge.
The compact report does not contain the raw Codebase metric inventory. Use
--metrics-output PATH for detector development or calibration. That sidecar
is deliberately outside the stable report contract.
HTML report
The offline React app renders a Reforge report: Issues, nested Evidence and measurements, typed Dataflow witnesses, per-analysis coverage, suppression totals, and optional baseline comparison. It does not render raw metrics, Flow IR, arbitrary JSON extensions, or internal ontology fields.
After frontend changes run:
cd web/report-app
npm ci
npm test
npm run test:e2e
npm run build
Commit the source together with regenerated assets/report-app.js and
assets/report-app.css plus their synchronized crates/reforge-output/assets
copies; the HTML renderer embeds the package-local assets and requires no
server or network.
Report format
The current report format uses schema_version = 27. reforge_schema::Report
contains schema_version, producer, target,
provenance, summary, suppression, coverage, issues, and optional
baseline_comparison. Unknown fields are rejected.
Provenance records identity scheme reforge-identity-v7, the evaluated scope
digest, per-analysis configuration and policy digests, and each evaluated
rule’s semantic version and evaluation digest.
An Issue contains kind = advisory | policy, explicit analysis and family,
typed Subject, readable prose, Evidence, an ri7-* ID, and a versioned
content_fingerprint (rc7-*). Subject entities contain independent key,
path, and optional
symbol fields; groups contain structured entity members. Symbol keys use
language, qualified owner, declaration kind, name, and signature or stable
disambiguator. Prose, ordering, checkout location, comments, and line numbers
do not define identity.
Evidence has an re7-* ID derived from rule and semantic anchor. Measurements,
thresholds, evidence-set changes, and substantive witness changes update the
Issue content fingerprint. Flow witnesses expose typed source/sink symbols,
ordered steps, hop counts, and exact, modeled, unresolved, or
unsupported resolution. Only all-exact, value-preserving paths can be policy
witnesses.
Coverage is keyed by analysis and language. Language entries include capability receipts for syntax, symbols, lexical scopes, local def-use, direct calls, call/return composition, field flow, and dynamic dispatch. Rule entries print once with maturity, activation source, status, observations, and limitations. Zero Evidence never erases the observed denominator.
Baseline comparison maps every current or previous Issue ID to new,
unchanged, updated, absent, or unknown, with an optional reason. A
matching ID with a changed content fingerprint is updated. Scope, relevant
configuration/policy, rule semantics/evaluation, analysis availability, or
coverage changes make otherwise unprovable additions/disappearances unknown.
Workspace identity mismatch is an error. Producer name and identity scheme must
match, but producer versions and unrelated analysis sets may differ.
Older report formats are rejected rather than silently converted. Regenerate them with the current analyzer so their findings and Coverage describe the same analysis behavior.
Architecture
tools/reforgeis a thin CLI and configuration boundary.crates/reforge-engineowns workspace indexing, execution planning, Codebase and Dataflow analysis, evidence aggregation, and report creation.crates/reforge-schemaowns the publicReport, stable identities, typed witnesses, coverage, and baseline comparison.crates/reforge-outputowns human, JSON, YAML, SARIF, and embedded HTML rendering.web/report-appowns the offline HTML interface.
The engine builds one shared workspace index. Each selected source is walked,
read, language-classified, and parsed once; Codebase and Dataflow consume the
same indexed sources. The typed Config selects either or both analyses and
owns scope, thresholds, policies, and suppressions.
The public model starts at the report. An analysis is an execution selection and a Coverage key, not a wrapper around the report:
Report
├── Coverage by analysis
│ ├── language counts
│ ├── rule execution
│ └── limitations
└── Issue
└── Evidence
├── Measurement
├── Location
└── optional Flow witness
Detectors produce DetectedEvidence with a semantic anchor and no internal
report ID. One static RuleSpec registry supplies analysis ownership,
aggregation family, output subject kind, input observation source, language
support, measurements, and a rule-specific description. Families
are an aggregation and identity mechanism, not an additional user workflow:
after suppression, the engine groups Evidence by family and Subject into
Issues; schema projection alone creates stable Evidence IDs.
The engine returns the public Report directly. Debug metrics and Flow IR take
separate explicit sidecar paths and never enter the report. Flow IR is only
materialized when --flow-ir-output is requested.
Contributing
Core user-facing work starts at tools/reforge and an explicit
the typed Config; do not add another peer analyzer CLI for a core rule. Every new
rule must declare exactly one Codebase or Dataflow owner, a namespaced family,
description, supported languages, default state, measurements, and focused
positive/negative tests in the rule registry.
Dataflow frontends emit the language-neutral Flow IR. Add exact edges only for semantics the frontend can prove, record dynamic/unsupported behavior as coverage limitations, and test positive, negative, partial, and unsupported cases. Stable path detectors require ordered source-to-sink witnesses, budget/cycle tests, at least five positive and five negative microfixtures, and documented real-project calibration before maturity changes.
Run cargo test --workspace --all-targets --all-features, all-target Clippy with warnings denied, both analysis self-checks, report-app unit/browser/build checks, installer tests, and docs build before review. Frontend changes must regenerate the committed embedded assets.
This project follows the repository guidelines in AGENTS.md. Keep changes
small, behavior-focused, and covered by targeted tests.
Setup
Install Rust 1.85 or newer, then run:
cargo build
cargo test
For a quick end-to-end smoke test:
cargo run -p reforge-cli -- analyze . --reproducible
For reproducible machine-readable output:
cargo run -p reforge-cli -- analyze . --analysis codebase --set codebase.churn=off --reproducible --output json
Development Workflow
Use cargo fmt before review:
cargo fmt
Run tests:
cargo test
Run Clippy before larger changes:
cargo clippy --all-targets --all-features
When report formatting or schema behavior changes, include sample human, HTML, JSON, YAML, or SARIF output in the pull request description.
Report App Development
The React report app requires Node.js ^20.19.0 or >=22.12.0 and npm; CI uses
Node.js 22. Vite 8 is installed from the locked frontend dependencies, so use
the package scripts instead of a global Vite installation:
cd web\report-app
npm ci
npm run test
npm run build
npx playwright install chromium
npm run test:e2e
The build refreshes assets/report-app.js and assets/report-app.css, then
synchronizes them into crates/reforge-output/assets. Rust
embeds those files in offline HTML reports, so commit both generated asset sets
with the frontend source change.
The Playwright suite generates a report with deliberately strict thresholds
and opens the final self-contained HTML file in Chromium. It covers browser
rendering, report interactions, and desktop/mobile layout. Failure screenshots,
traces, and videos are written below target/playwright; the HTML test report
is written to web/report-app/playwright-report in CI.
Documentation Site
The documentation site uses mdBook 0.5.4. Install that exact version before building or serving the site locally:
cargo install mdbook --version 0.5.4 --locked
On Windows, generate the Codebase example report and serve the site with:
.\scripts\serve-docs.ps1
Build static files into target/docs-site without starting a server:
.\scripts\build-docs.ps1
On macOS or Linux, use the matching shell scripts:
sh scripts/serve-docs.sh
sh scripts/build-docs.sh
The published documentation root is
https://lylemi.github.io/Reforge/; the generated Codebase example is published at
https://lylemi.github.io/Reforge/sample/. Repository administrators must set
Settings > Pages > Build and deployment > Source to GitHub Actions before
the Pages workflow can deploy for the first time. Keep the github-pages
environment restricted to the main branch; the workflow also enforces that
branch boundary for manual runs.
Tests
Unit tests live next to the modules they exercise under #[cfg(test)] or in
module-specific test files included from the module. There is currently no
separate tests/ directory.
Add tests for:
- CLI parsing and default values when flags change.
- Config precedence and discovery when configuration changes.
- Source collection exclusions, thresholds, ordering, and report fields.
- Detector behavior, including false-positive guards.
- Output stability for human, HTML, JSON, YAML, and SARIF report changes.
Name tests by behavior, such as parses_output_format or
groups_similar_functions.
Style
Use idiomatic Rust formatted by cargo fmt. Prefer the existing module split:
cli, scan, model, detectors, evidence_analysis, workflow, and output.
Use snake_case for functions, variables, modules, and test names. Use
PascalCase for structs, enums, and traits. Keep CLI flags long,
descriptive, and kebab-case.
Avoid unrelated refactors in behavior changes. If a refactor is needed to make a feature safe, keep it scoped and covered by tests.
Report Compatibility
JSON, YAML, and SARIF reports are external interfaces. When fields are added, removed, or renamed:
- Update
reforge_schema::REPORT_SCHEMA_VERSION. - Update
docs/report-schema.md. - Update output tests.
- Mention the compatibility impact in the pull request.
Consumers should rely on stable Issue and Evidence IDs, typed measurements, Coverage, and typed Dataflow witnesses. The report format does not emit priority, confidence, severity, or hotspot ranking.
Commits and Pull Requests
Use Conventional Commits:
feat(codebase): detect directories with many source files
fix(report): keep JSON output stable
docs: add report schema reference
Keep descriptions imperative, lowercase, and without a trailing period. Keep commits scoped to one behavior change.
Pull requests should describe:
- User-visible effect.
- Validation commands run.
- Related issues.
- Sample human, HTML, JSON, YAML, or SARIF output when report formatting changes.
Do not commit generated outputs, dependency directories, build artifacts, or
local analysis artifacts. The checked-in assets/report-app.js and
assets/report-app.css bundles and their crates/reforge-output/assets copies
are the sole generated-output exception because
the Rust HTML renderer embeds them.