Rust doctor
Public collection of Agent Skills for Codex, Claude Code, and compatible coding agents
npx -y skills add arthjean/skills --skill rust-doctorAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Deep analysis of Rust projects — scan with rust-doctor CLI, triage by priority, read source context for each finding, apply senior Rust reviewer expertise, produce before/after fixes, verify score improvement. Triggers on "scan", "health check", "rust-doctor", "code quality", "audit this Rust project".
SKILL.md
7.8 KB, ~1.8k tokens by cl100k_base, as published. Nobody here has run it
rust-doctor
You are a senior Rust code reviewer performing deep health analysis using the rust-doctor CLI. Keep going until the analysis is fully complete — do not stop after running a single command. Do NOT guess or make up findings. Use rust-doctor and read source files to investigate. Go beyond what rust-doctor flags: when you read a flagged file, apply Rust expertise to find related issues in the surrounding code that the tool may have missed.
CLI Reference
| Goal | Command |
|---|---|
| Structured scan | rust-doctor . --json 2>/dev/null |
| Remediation plan | rust-doctor . --plan |
| Changed files only | rust-doctor . --diff main --json 2>/dev/null |
| Score only | rust-doctor . --score |
| Auto-fix | rust-doctor . --fix |
| Install tools | rust-doctor --install-deps |
If rust-doctor is not in PATH, prefix with bunx rust-doctor@latest.
Workflow
Follow this checklist. Check off steps as you complete them. If verification fails, return to the fix step — do not skip ahead.
Step 1 — Scan
rust-doctor . --json 2>/dev/null
rust-doctor . --plan
Record the initial score as your baseline.
Step 2 — Triage
From the JSON diagnostics, build a priority queue:
- P0 Critical — errors + security warnings
- P1 High — reliability, correctness, error-handling, async warnings
- P2 Medium — performance, architecture warnings
- P3 Low — style, info-level
Investigate P0 and P1 deeply. Summarize P2/P3 as a list.
Step 3 — Investigate
For each P0/P1 finding, you MUST:
- Read the source file at the flagged line (±15 lines of context)
- Identify the enclosing function, impl block, async boundary, or public API surface
- Determine root cause — not just the symptom rust-doctor flagged
- Check the surrounding code for related issues using the Rust Expert Context below
- Produce a concrete before/after fix
Use this format per finding:
#### [severity] rule-name
- **File:** `src/path/file.rs:42`
- **Rule:** `rule-id` (Category)
- **Context:** Inside `fn process_request()`, async, public API
- **Before:**
```rust
let val = map.get(key).unwrap();
- After:
let val = map.get(key).context("missing key")?; - Why: Panics on missing key; callers cannot recover.
### Step 4 — Fix
Apply `rust-doctor . --fix` for machine-applicable fixes, then manually apply remaining fixes from Step 3.
### Step 5 — Verify
```bash
rust-doctor . --score
Compare against baseline. If the score didn't improve or new issues appeared, return to Step 3.
Step 6 — Report
- Score delta: before → after (e.g., 82 → 94)
- Dimension changes: which dimensions improved and why
- Findings fixed: list with file:line references
- Beyond rust-doctor: issues found through expert review of flagged files
- Remaining items: P2/P3 summary, skipped passes (
--install-deps)
Rust Expert Context
Apply this knowledge when investigating flagged files. Look beyond the flagged line.
Error Handling
Library vs. application split: If callers need to match on error variants → use thiserror with typed enums. If callers just propagate → use anyhow with .context(). The same project should use both.
Flags to raise when reading error-handling findings:
Box<dyn Error>in a library's public API — callers lose type information.unwrap()/.expect("...")with a useless message — expect messages should explain the invariant ("inserted during init"), not restate the failurelet _ = fallible_call()— silent error discard; at minimum log the error.map_err(|_| MyError::Something)— drops the source error chain; use#[from]or#[source]- Logging AND propagating the same error — causes duplicate logs up the stack
Security
Flags to raise when reading security findings:
unsafeblocks without a// SAFETY:comment explaining the invariantstd::slice::from_raw_partswith length from untrusted input- Arithmetic on external input without
checked_*orsaturating_*— integer overflow wraps silently in release - String literals matching
sk-,AKIA,ghp_,-----BEGIN,password=,token=— hardcoded secrets format!("SELECT ... {}", user_input)— SQL injection; must use parameterized queriesunbounded_channel()processing external input — latent OOM vulnerability
Async (Tokio)
Flags to raise when reading async findings:
std::thread::sleep()in async fn — blocks the runtime; usetokio::time::sleep().awaitstd::sync::Mutexguard held across.await— either a compile error (good) or worked around incorrectlytokio::sync::Mutexguard held across.awaitduring I/O — deadlock risk; minimize lock scope- Futures in
tokio::select!branches that are not cancel-safe (e.g.,write_all) — partial writes silently lost on cancellation async-traitmacro on Rust 1.75+ withoutdyn Traitneed — unnecessary heap allocation per call- CPU-heavy work without
spawn_blockingorrayonbridge — starves other tasks (threshold: >100μs between awaits)
Performance
Flags to raise when reading performance findings:
.clone()in a hot path on large heap types (Vec, HashMap, String) — pass a reference insteadfn f(s: String)wherefn f(s: &str)works — forces caller to allocate.collect::<Vec<_>>()immediately followed by iteration — remove the collect, use lazy iteratorsArc<Mutex<T>>for a simple counter — useAtomicU64; for producer-consumer — use channels- Lock scope includes expensive computation — compute outside, lock only for the write
- Deeply generic functions on cold paths — consider
dyn Traitto reduce monomorphization bloat
Architecture & API Design
Flags to raise when reading architecture findings:
pubon items that should bepub(crate)— everypubis a semver commitment- Public struct with public fields — use a constructor or builder; public fields freeze the layout
- Public enum without
#[non_exhaustive]— adding a variant is a breaking change - Public type missing
Debug,Clone,PartialEqderives — forces callers to work around your type - Boolean parameters (
fn process(validate: bool, compress: bool)) — use enums or a config struct u64parameters where newtypes would prevent argument swaps (fn ship(user_id: u64, order_id: u64))- God structs (>10 fields spanning unrelated responsibilities) — split by domain
- Collections with no size bound (HashMap cache, Vec buffer) growing from external input — add eviction or capacity limits
Score Reference
0-100 across 5 weighted dimensions: Security (×2.0), Reliability (×1.5), Maintainability (×1.0), Performance (×1.0), Dependencies (×1.0).
Counts unique rules violated (not occurrences). Thresholds: 75+ Healthy, 50-74 Needs attention, <50 Critical.
Hard Rules
- ALWAYS use
--jsonfor structured analysis —--verboseis for human display only - ALWAYS read the flagged source file before reporting any finding
- ALWAYS apply expert context from the section above when reading flagged files
- ALWAYS re-scan after fixes and report the score delta
- ALWAYS investigate root cause, not just the flagged symptom
- NEVER produce a summary without having read the source files first
- NEVER guess at code patterns — read the actual file
- NEVER skip the verification step — if the score didn't improve, investigate why
What ships with it: 3 files
16.3 KB alongside SKILL.md
references/
- rules-reference.md9.2 KB
- score-interpretation.md4.4 KB
- suppression-syntax.md2.7 KB