Thanks for taking the time to contribute. rclean is a small CLI with
a deliberately narrow scope — these notes capture the working patterns
so a PR can land cleanly the first time.
rclean deletes files. The trust model is the product:
scannever deletes.clean --allselects onlysafecandidates unless--include-cautionis passed. Blocked candidates are never selected, even with--include-blocked.- Plan-based cleanup re-validates every path against the live filesystem before deleting, refuses to follow new symlinks, and rejects plans whose roots have changed shape since the scan.
A change that weakens any of these guarantees needs an explicit
discussion in the PR before code, ideally as a SPEC update under
docs/specs/ first. See SECURITY.md for the threat
model and reporting workflow.
- Edition: Rust 2024.
- MSRV:
rust-version = "1.95"inCargo.toml. CI verifies the pinned MSRV on Ubuntu; PRs that need a newer toolchain must bumprust-versionand explain why in the commit message. - OS coverage: CI runs
fmt,clippy,test, and a release build on Ubuntu, macOS, and Windows. Platform-specific code must be gated withcfg(unix)/cfg(windows)and have at least one platform-gated test intests/cross_platform.rs.
Run these before opening a PR — they mirror what CI runs:
cargo fmt -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test
cargo build --release
rustup run 1.95 cargo build --all-targets --all-features
rustup run 1.95 cargo testIf your change is performance-sensitive, also run the benchmark suite
(see benches/ and docs/perf/) and include the before/after numbers
in the PR body.
AI agents should start with AGENTS.md. Small docs-only
changes can be handled directly with focused verification. Substantial
rule, safety, CLI, or multi-module changes need a linked GitHub issue
and, when behavior is ambiguous or risky, a SpecRail packet under
specs/GH<number>/.
- Use the repository PR template and fill in the safety/scope and verification sections. If a checklist item is not applicable, say why in the PR body instead of deleting it.
- Small and focused. One concern per PR. If a refactor and a fix are tangled, land the refactor first as a pure-rename PR, then the fix.
- Conventional commits. Existing history uses
feat:,fix:,perf:,refactor:,test:,docs:,chore:prefixes with an optional scope (e.g.perf(scan): ...). - Sign-off. Commits should include a
Signed-off-by:trailer (git commit -s). The Lore convention also encourages capturing why the change exists, not just what changed. - No bundled fixes. Don't roll style edits into behavior changes. Style-only changes are their own commit and PR.
- File size: single-file limit is 800 lines (hard ceiling). When
a module approaches that, split it into a directory module —
src/rules/is the existing example. The split should be a separate pure-rename PR before any feature work lands on top. - No silent degradation. Errors that cause user-visible wrong
output must be raised, not logged at
warningand replaced with a fallback. Optional features that can degrade safely (e.g. cache write failure) are the exception and must mark the degraded path explicitly. - No new aliases. When renaming a function, type, or flag, remove every old reference in the same change — don't leave deprecated aliases.
- Tests with every fix. Every bug fix must add a regression test that fails before the fix and passes after. Refactors must keep existing tests green.
- Symlink behavior is part of the contract: symlinked candidates
resolve to
Safety::Blockedin bothscanandexplain. Anything touching the walker orapply_path_safetyneeds an explicit symlink case in tests.
Built-in rules live in src/rules/, one file per ecosystem. The
contract is classify_candidate(parent, name, path) -> Option<CandidateDraft>:
- Pick the right file (
src/rules/node.rs,python.rs, ...). If the ecosystem is new, add a sibling file and register it insrc/rules/mod.rsandsrc/rules/catalog.rs. - Add at least one positive test in
tests/rules.rsand one negative test that confirms the rule does not fire without its marker. - Generic directory names (
build,dist,out,target,vendor) require a project marker — never classify them by name alone. - Update the Supported Ecosystems table in
README.md.
User-extensible rules live in .rclean.toml (per scan root). User
rules layer after built-in rules and cannot produce Safety::Blocked.
The file format is documented in the README.
- Functional bugs (wrong candidate, wrong size, wrong category):
open a
scan false positive report
with a minimal reproducible directory layout (
mkdir -pscript is ideal). - Cleanup behavior that looks risky or surprising: open a cleanup safety concern with the command, safety tier, and sanitized output.
- New ecosystem rules, install/package requests, output modes, and documentation gaps: open a feature request.
- Security or trust-model issues: follow the private disclosure
process in
SECURITY.md— do not file a public issue.
Versioning is 0.1.x for the v0.1 series; behavior-breaking changes
require either a minor bump (post-1.0) or an explicit migration note
in CHANGELOG.md. The roadmap for the current minor series lives in
docs/specs/v0.1.x-roadmap.md.