The one-command health check for your Rust project. rust-doctor scans for security, performance, correctness, architecture, and dependency issues, then folds everything into a single 0–100 score with diagnostics you can act on.
It runs cargo clippy, cargo-audit, cargo-deny, cargo-geiger, and 19 custom AST rules in one pass, and ships as a CLI, a library crate, an MCP server, an npm package, and a GitHub Action — so it works in your terminal, your CI, and inside Claude Code, Cursor, or any MCP agent.
$ rust-doctor # rust-doctor scanning its own codebase
◠ ◠ rust-doctor
▽ 99 / 100 Great
████████████████████████████████████████
Security 99 · Reliability 99 · Maintainability 100 · Performance 99 · Dependencies 99
✓ 0 errors ⚠ 44 warnings ℹ 42 infos · 60 files scanned in 32.9sNo Rust toolchain required — npx downloads a pre-built native binary for your platform:
npx rust-doctor # scan the current directory and print the scorePrefer cargo? cargo install rust-doctor. Want it in your AI agent? npx rust-doctor setup. Other formats are in Installation.
demo.mp4
Rust already has excellent point tools. rust-doctor runs them together, adds rules they don't cover, and turns the result into one number you can track over time.
| You're using | It gives you | rust-doctor adds |
|---|---|---|
cargo clippy |
700+ built-in lints | Category + severity mapping, 19 custom AST rules (security, async, framework, architecture), and a single 0–100 score |
cargo audit / cargo deny |
CVE and supply-chain checks | One pass that also runs clippy, geiger, and machete — skipping gracefully when a tool isn't installed |
| Separate CI steps | Each tool's own output | One command with --json, --sarif, --diff, --score, and PR comments |
| Claude Code / Cursor | Code generation | An MCP server and a slash-command skill, so the agent scans, scores, and fixes as it writes |
- 700+ clippy lints with explicit severity overrides and category mapping
- 19 custom AST rules via syn: error handling, performance, security, async, architecture, and framework anti-patterns
- Async anti-pattern detection: blocking calls and
block_oninside an async context - Framework-aware rules: tokio, axum, actix-web — only run when the dependency is present
- Supply-chain auditing: CVEs via
cargo-audit, bans/licenses viacargo-deny, unsafe viacargo-geiger, unused deps viacargo-machete - A 0–100 health score across five weighted dimensions, with an ASCII doctor that reacts to the result
- MCP server: 4 read-only tools + 2 expert audit prompts for Claude Code, Cursor, Windsurf, or any MCP client
- Diff mode:
--diffscans only changed files for fast CI feedback - Workspace support: scan every crate or pick specific members
- Inline suppression:
// rust-doctor-disable-next-line <rule> - Output modes: terminal,
--json,--score(bare integer for CI),--sarif(GitHub code scanning) --fix: apply machine-applicable fixes to source files- Setup wizard:
rust-doctor setupauto-detects Claude Code, Cursor, and Windsurf and wires up MCP or installs the skill in one command - Distributed everywhere: CLI binary, library crate, MCP server, npm package, and GitHub Action
npx rust-doctor --mcpOr install globally:
npm install -g rust-doctorThis downloads a pre-built native binary for your platform — no Rust toolchain required.
cargo install rust-doctorcargo binstall rust-doctorcurl -fsSL https://github.com/ArthurDEV44/rust-doctor/releases/latest/download/install.sh | bashirm https://github.com/ArthurDEV44/rust-doctor/releases/latest/download/install.ps1 | iexDownload pre-built binaries from GitHub Releases.
Available platforms:
x86_64-unknown-linux-gnuaarch64-unknown-linux-gnux86_64-apple-darwinaarch64-apple-darwinx86_64-pc-windows-msvc
# Scan current directory
rust-doctor
# Scan a specific directory
rust-doctor /path/to/project
# Get bare score for CI
rust-doctor --score
# JSON output
rust-doctor --json
# Scan only changed files
rust-doctor --diff
# Scan against a specific branch
rust-doctor --diff main
# Fail CI on errors
rust-doctor --fail-on error
# Scan specific workspace members
rust-doctor --project core,api
# Verbose output with file:line details
rust-doctor --verbose
# Install missing external tools (cargo-deny, cargo-audit, etc.)
rust-doctor --install-deps
# Run as MCP server
rust-doctor --mcp
# Setup wizard — configure AI agents automatically
rust-doctor setuprust-doctor returns distinct exit codes so CI pipelines can tell a quality-gate failure apart from a crash:
| Code | Meaning |
|---|---|
0 |
Success — scan completed and all quality gates passed |
1 |
Setup error — MCP server, setup wizard, or --install-deps failed |
2 |
Scan error — project discovery/compile failure or output rendering failed |
3 |
Quality gate failed — score below [score] fail_below, or --fail-on threshold reached |
Gate the build on a quality failure without masking a crash:
rust-doctor --fail-on error
if [ $? -eq 3 ]; then
echo "Quality gate failed"
exit 1
fiThe fastest way to integrate rust-doctor with your AI coding agent:
npx rust-doctor@latest setupThe wizard auto-detects installed agents (Claude Code, Cursor, Windsurf) and lets you choose:
- CLI + Skills (default) — installs a
SKILL.mdthat teaches your agent to use the rust-doctor CLI with deep analysis capabilities - MCP Server — configures the
rust-doctor --mcpstdio server in your agent's config file
The wizard handles detection, configuration, and verification in one command. For manual setup, see the sections below.
rust-doctor includes a built-in Model Context Protocol server, allowing AI coding assistants to scan and analyze Rust projects directly.
| Tool | Description |
|---|---|
scan |
Scan a Rust project for code health issues. Returns diagnostics with a 0–100 health score. |
score |
Get the health score (0–100) of a Rust project as a single integer. |
explain_rule |
Get a detailed explanation of a rule: what it checks, why it matters, and how to fix violations. |
list_rules |
List all available rules with their categories and severities. |
All tools are read-only (readOnlyHint: true).
| Prompt | Description |
|---|---|
deep-audit |
Comprehensive 6-phase expert audit: codebase exploration, static analysis, deep code review (51-item checklist), best practices research, synthesis report, and remediation choices (implement all / generate PRD / manual). |
health-check |
Quick scan + prioritized remediation plan (P0–P3) + fix workflow. |
Automatic setup (recommended):
rust-doctor setup # detects Claude Code and configures MCP or installs skillOr one-command MCP install:
claude mcp add --transport stdio rust-doctor -- npx -y rust-doctor --mcpOr via Claude Code plugin:
/plugin install rust-doctor@ArthurDEV44/rust-doctor
Or add manually to your ~/.claude/settings.json:
{
"mcpServers": {
"rust-doctor": {
"command": "rust-doctor",
"args": ["--mcp"]
}
}
}Or share with your team via .mcp.json in your project root (committed to git):
{
"mcpServers": {
"rust-doctor": {
"command": "npx",
"args": ["-y", "rust-doctor", "--mcp"]
}
}
}Add to your .cursor/mcp.json:
{
"mcpServers": {
"rust-doctor": {
"command": "npx",
"args": ["-y", "rust-doctor", "--mcp"]
}
}
}Add to your .vscode/settings.json:
{
"mcp": {
"servers": {
"rust-doctor": {
"type": "stdio",
"command": "npx",
"args": ["-y", "rust-doctor", "--mcp"]
}
}
}
}Add to your ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"rust-doctor": {
"command": "npx",
"args": ["-y", "rust-doctor", "--mcp"]
}
}
}rust-doctor uses stdio transport. Any MCP client that supports stdio can connect by running rust-doctor --mcp.
Built with rmcp v1.x (official Rust MCP SDK).
If you prefer slash commands over MCP servers, rust-doctor ships a Claude Code skill.
Automatic install (recommended):
rust-doctor setup # choose "CLI + Skills", select Claude CodeOr via npx:
npx skills add https://github.com/ArthurDEV44/rust-doctor --skill rust-doctorOr copy manually:
cp -r skills/rust-doctor/ ~/.claude/skills/rust-doctor/Usage:
/rust-doctor # scan current project
/rust-doctor --diff # scan changed files only
/rust-doctor --fix # scan + apply fixes
/rust-doctor --plan # scan + remediation plan
/rust-doctor src/ # scan a specific directory
The skill runs the rust-doctor CLI under the hood, parses the output, categorizes findings by priority, and provides actionable fix guidance with before/after code.
- uses: ArthurDEV44/rust-doctor@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
fail-on: warningThe action posts a PR comment with the health score, error/warning counts, and top diagnostics.
Create a rust-doctor.toml in your project root, or add [package.metadata.rust-doctor] to your Cargo.toml:
# rust-doctor.toml
verbose = false
fail_on = "none"
[ignore]
rules = ["excessive-clone", "string-from-literal"]
files = ["**/generated/**", "tests/**"]CLI flags override config file values.
// rust-doctor-disable-next-line unwrap-in-production
let value = some_option.unwrap();
let x = risky_call(); // rust-doctor-disable-lineThese rules analyze the syntax tree only (via syn): no type resolution, no
macro expansion. They run fast and offline, but emit a heuristic signal, not
a type-checked verdict — calibrate confidence accordingly. Findings are tagged
heuristic in --json and SARIF output, and marked ~heuristic in the
terminal. Rules flagged ⚠ have known structural blind spots (see below).
| Category | Rule | Severity |
|---|---|---|
| Error Handling | unwrap-in-production ⚠ |
Warning |
| Error Handling | panic-in-library |
Error |
| Error Handling | box-dyn-error-in-public-api |
Warning |
| Error Handling | result-unit-error |
Warning |
| Performance | excessive-clone |
Warning |
| Performance | string-from-literal |
Info |
| Performance | collect-then-iterate |
Warning |
| Performance | large-enum-variant ⚠ |
Warning |
| Performance | unnecessary-allocation |
Warning |
| Architecture | high-cyclomatic-complexity |
Warning |
| Security | hardcoded-secrets |
Error |
| Security | unsafe-block-audit |
Warning |
| Security | sql-injection-risk ⚠ |
Error |
| Async | blocking-in-async ⚠ |
Error |
| Async | block-on-in-async |
Error |
| Framework | tokio-main-missing |
Error |
| Framework | tokio-spawn-without-move |
Error |
| Framework | axum-handler-not-async |
Warning |
| Framework | actix-blocking-handler |
Warning |
Without type information these rules have documented blind spots. They're still worth surfacing, but a finding is a prompt to look, not a confirmed defect:
unwrap-in-production— matches.unwrap()/.expect()syntactically; cannot tell a provably-infallible unwrap from a risky one.large-enum-variant— counts a variant's fields, not its byte size; a few wide-type fields can outweigh many small ones.blocking-in-async— flags known blocking calls by name inside async fns; cannot follow calls into other functions or resolve aliased imports.sql-injection-risk— flags string-built queries heuristically; cannot confirm the interpolated value is actually untrusted input.
rust-doctor runs cargo clippy with pedantic, nursery, and cargo lint groups. 75+ lints have explicit category and severity overrides across: Error Handling, Performance, Security, Correctness, Architecture, Cargo, Async, Style. Unlike the custom rules above, clippy resolves types against the compiler, so its findings are more authoritative — they are not tagged heuristic.
These tools are optional — rust-doctor gracefully skips any that are missing and shows which passes were skipped. Run rust-doctor --install-deps to install them all at once.
| Tool | Install | What it does |
|---|---|---|
| clippy | rustup component add clippy |
700+ lint checks |
| cargo-deny | cargo install cargo-deny |
Supply-chain checking (advisories, licenses, bans) |
| cargo-audit | cargo install cargo-audit |
CVE vulnerability scanning |
| cargo-geiger | cargo install cargo-geiger |
Unsafe code auditing across dependency tree |
| cargo-machete | cargo install cargo-machete |
Unused dependency detection |
| cargo-semver-checks | cargo install cargo-semver-checks |
Semver violation detection |
rust-doctor is available as a library crate:
use std::path::Path;
// Discover the project (finds Cargo.toml, loads config)
let (dir, info, config) = rust_doctor::discovery::bootstrap_project(
Path::new("/path/to/project"), false,
)?;
// Resolve config with defaults
let resolved = rust_doctor::config::resolve_config_defaults(config.as_ref());
// Run the scan
let result = rust_doctor::scan::scan_project(&info, &resolved, false, &[], true)?;
println!("Score: {}/100 ({})", result.score, result.score_label);Full API docs are on docs.rs/rust-doctor.
Read the 0–100 score as a compass, not a thermometer. It points you toward
the weakest dimension; it isn't a precision measurement. The per-dimension
scores (shown in the terminal box and in --json) carry the real signal — they
tell you where to act.
The score is a weighted average across 5 dimensions:
| Dimension | Weight | Covers |
|---|---|---|
| Security | ×2.0 | Security rules (hardcoded secrets, unsafe, SQL injection) |
| Reliability | ×1.5 | Correctness, error handling, async, framework |
| Maintainability | ×1.0 | Architecture, style |
| Performance | ×1.0 | Performance |
| Dependencies | ×1.0 | Cargo, dependencies, advisory findings (RUSTSEC / cargo-deny) |
Each dimension starts at 100 and loses points per unique rule violated, weighted by severity:
dimension = 100 − (unique_error_rules × 1.5) − (unique_warning_rules × 0.75) − (unique_info_rules × 0.25)
The dimension is clamped to [0, 100], and the overall score is the weighted
average of the five, also clamped to [0, 100].
The score counts unique rules, not occurrences — fixing one .unwrap() won't
move it, but removing the last .unwrap() drops the penalty entirely.
| Score | Label | Doctor |
|---|---|---|
| 75–100 | Great | ◠ ◠ |
| 50–74 | Needs work | • • |
| 0–49 | Critical | x x |
- Dimension saturation. Penalties are linear and the floor is 0, so once a
dimension accumulates ~67 distinct Error-severity rules (
100 ÷ 1.5), it sits at 0 and further distinct rules in that dimension stop moving the number — it's directional past that point, not proportional. - Heuristic inputs. The custom AST rules are
syn-only (no types, no macro expansion), so part of what feeds the score is a heuristic signal — see Rules. Clippy and external-tool findings are type-aware. The score does not currently weight heuristic vs type-aware findings differently. - Hand-tuned weights. The dimension weights and severity penalties are deliberate but not empirically calibrated; treat cross-project score comparisons with caution.
- Empty projects. A directory with no Rust source files scores 100 and emits
No Rust source files found— expected, not a clean bill of health.
Contributions are welcome. Read CONTRIBUTING.md for the dev
setup, the CI gates to run before opening a PR (cargo fmt, cargo clippy,
cargo test), and the guide to authoring a new rule. By participating you agree
to the Code of Conduct. For security issues, follow the
Security Policy — please don't open a public issue.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.