A skill for AI coding agents (Claude Code, Cursor, pi, and others) that writes idiomatic, safe Rust.
It runs a verification loop (cargo clippy -- -D warnings, cargo test) plus 16 judgment rules for what clippy enforces only mechanically. The machine verifies what it can; prose covers the judgment it cannot.
LLMs are now good enough at Rust that the compiler and clippy are the reliable verifier. Hundreds of community rules are already machine-encoded as lints. Restating them as prose the model can't hold every turn adds clutter and drifts.
This skill keeps the hard loop (clippy, test) plus the judgment layer clippy can't make: parse-don't-validate, unsafe with justified SAFETY comments, error types, no lock across await, cancellation safety, executor blocking, naming, newtypes. One file, the agent holds it.
Copy SKILL.md into your agent's skills directory.
mkdir -p ~/.pi/agent/skills/rust-code
curl -fsSL https://raw.githubusercontent.com/renflowerz/rust-code-skill/main/SKILL.md \
-o ~/.pi/agent/skills/rust-code/SKILL.mdPlace SKILL.md in your .claude/skills/ or reference it from CLAUDE.md.
cargo clippy -- -D warnings # zero warnings, non-negotiable
cargo test # tests passClippy is the primary verifier. The compiler is the second; the borrow checker catches what no prose can.
- Parse, don't validate. Invalid states should not compile.
unsafeneeds a// SAFETY:comment immediately above the block, with the exact invariant plus a justification.- Error design is a contract decision.
anyhowdowncasts fine; typed enums (thiserror) put the failure set in the type system for exhaustive matching. Typed when callers react to specific failures, anyhow when they log/propagate. - No
.unwrap()or.expect()on external input paths. - No locking across
.await. Extract, drop the guard, then await. - Newtypes over bare primitives in public APIs.
- No incidental smart pointers in signatures.
Box<dyn Trait>and returnedArchandles are fine;Arc<Mutex<Everything>>plumbing is not. - Conversion naming:
as_/to_/into_. ImplementFrom, getIntofree. - Iteration over manual indexing.
- Derive what the API promises.
#[non_exhaustive]on growing types. Libraries don't panic; returnResult. - Native
async fnin traits (stable since 1.75) is the default.async-trait/trait_variantonly fordyndispatch. Futures underselect!/aborts must be cancellation-safe. - Don't block the executor. Sync I/O and CPU loops go to
spawn_blocking. - Dependencies: prefer std, check the tree before adding.
serde:deny_unknown_fieldsinbound, version-tolerant storage.- Measure before optimizing. No speculative
unsafewithout a profile. - Comments explain why.
cargo docbuilds clean.
See SKILL.md for the full rules with reasoning and a review checklist.
MIT