⏳ This skill is pending AI review.
Scores will appear once the review pipeline completes.
rust-best-practices
>-
Choose how to use this skill
You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.
1. Native installer
This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.
Do not guess an installer command or replace an existing version without reviewing the diff.
2. Complete package recommended
Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.
No complete ProSkills package is published for this listing yet.3. Prompt-only
Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.
Need only the instruction file?
Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.
No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.
// RATINGS
Not yet listed on ClawHub or SkillsMP
// README
Beautiful Rust
Three standard Agent Skills and a lints config that teach coding agents to write, review, port, and enforce idiomatic Rust:
rust-best-practicesloads whenever an agent writes or changes Rust, and steers it toward idiomatic, robust, maintainable code.rust-reviewreviews existing Rust code, a file, a crate, or a diff, and writes a prioritized report where every finding cites the rule it breaks and shows the fix.rust-portports C, C++, Python, Go, or JavaScript to idiomatic Rust with the same behavior, porting the original tests first so you can prove the two match.lints/is a drop-in clippy configuration that enforces the machine-checkable rules in CI.
They work with Claude Code, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, and any other agent that reads the Agent Skills format. Every code example in the skills compiles on stable Rust, and every lint in the config was checked against current clippy.
The guidance is distilled from five sources, with a condensed digest of each bundled in the skill so the agent can consult the original reasoning when it needs to:
- Google Rust Style Guide
- Rust API Guidelines (official rust-lang checklist)
- Effective Rust by David Drysdale
- Rust Design Patterns (idioms, patterns, anti-patterns)
- Microsoft Pragmatic Rust Guidelines
Where the sources disagree, the skill picks a side and says why.
What it changes
Asked for a small semver-parsing library, an agent without the skill produced working
code with public fields, no # Errors docs, and unwrap() in its doc examples. With the
skill, the same agent kept the fields private, documented failure modes, and wrote doc
examples users can copy safely. Condensed from those two runs:
// Without the skill
/// A semantic version. The fields are public for convenience.
pub struct Version {
pub major: u64,
pub minor: u64,
pub patch: u64,
pub pre: Vec<Identifier>,
pub build: Vec<String>,
}
impl Version {
/// Parses a version string.
///
/// ```
/// let v = Version::parse("1.2.3").unwrap();
/// ```
pub fn parse(s: &str) -> Result<Version, ParseError> { /* ... */ }
}
// With the skill
/// A semantic version. Equality, hashing, and ordering ignore build metadata.
pub struct Version {
major: u64,
minor: u64,
patch: u64,
pre: Vec<Identifier>,
build: Vec<String>,
}
impl Version {
/// Parses a version string according to SemVer 2.0.0.
///
/// # Errors
///
/// Returns [`ParseVersionError`] if the string is empty, a numeric part has a
/// leading zero or overflows `u64`, or an identifier contains invalid characters.
///
/// ```
/// # use semver_lite::Version;
/// # fn main() -> Result<(), semver_lite::ParseVersionError> {
/// let v = Version::parse("1.2.3-beta.1")?;
/// assert_eq!(v.major(), 1);
/// # Ok(())
/// # }
/// ```
pub fn parse(s: &str) -> Result<Self, ParseVersionError> { /* ... */ }
/// Returns the major version number.
pub fn major(&self) -> u64 { self.major }
}
Across three test tasks (a library, a CLI, and refactoring a messy module), the skill passed 29 of 30 checks against 24 of 30 without it. See Testing the skills.
Install
Each skill is a folder under skills/: rust-best-practices/, rust-review/, and
rust-port/. Every option below puts those folders where your agent looks for skills.
Install all three; the review and port skills lean on the best-practices skill for style.
Any agent, one command
The skills installer supports most agents
(Node 22.20 or later):
npx skills add morganlinton/BeautifulRust
Add -g to install for your user instead of the current project, or -a <agent> to pick
an agent, such as -a codex or -a cursor.
Claude Code
Install it as a plugin so updates arrive with one command:
claude plugin install beautiful-rust --marketplace morganlinton/BeautifulRust
Inside a session, the same thing is:
/plugin marketplace add morganlinton/BeautifulRust
/plugin install beautiful-rust@beautiful-rust
This installs all three skills. They appear as /beautiful-rust:rust-best-practices,
/beautiful-rust:rust-review, and /beautiful-rust:rust-port, though you rarely need to
call them, since they trigger on their own. To try it for one session without installing, clone the repo
and run claude --plugin-dir ./BeautifulRust.
OpenAI Codex
Install it as a plugin:
codex plugin marketplace add morganlinton/BeautifulRust
codex plugin add beautiful-rust@beautiful-rust
This installs all three skills as beautiful-rust:rust-best-practices,
beautiful-rust:rust-review, and beautiful-rust:rust-port. The same package works in
the ChatGPT desktop app.
GitHub Copilot
With GitHub CLI 2.90 or later:
gh skill install morganlinton/BeautifulRust rust-best-practices
gh skill install morganlinton/BeautifulRust rust-review
gh skill install morganlinton/BeautifulRust rust-port
This installs into the current project by default. Add --scope user to install for your
user, or --agent <name> to install for a different agent.
Gemini CLI
gemini skills install https://github.com/morganlinton/BeautifulRust --path skills/rust-best-practices
gemini skills install https://github.com/morganlinton/BeautifulRust --path skills/rust-review
gemini skills install https://github.com/morganlinton/BeautifulRust --path skills/rust-port
Cursor or anything else: copy the folder
Clone the repo and copy the three skill folders into your agent's skills directory.
Most agents now read the shared .agents/skills/ location:
git clone https://github.com/morganlinton/BeautifulRust
mkdir -p ~/.agents/skills
cp -R BeautifulRust/skills/rust-* ~/.agents/skills/
| Agent | User directory | Project directory |
|---|---|---|
| Claude Code | ~/.claude/skills/ | .claude/skills/ |
| OpenAI Codex | ~/.agents/skills/ | .agents/skills/ |
| GitHub Copilot | ~/.copilot/skills/ or ~/.agents/skills/ | .github/skills/ or .agents/skills/ |
| Cursor | ~/.cursor/skills/ or ~/.agents/skills/ | .cursor/skills/ or .agents/skills/ |
| Gemini CLI | ~/.gemini/skills/ or ~/.agents/skills/ | .gemini/skills/ or .agents/skills/ |
Claude Code does not read .agents/skills/, so use its own directory or the plugin.
Restart the agent if the skill doesn't show up right away.
claude.ai
claude.ai takes one zip per skill, with the skill folder as the zip root:
cd skills
zip -r ../rust-best-practices.zip rust-best-practices -x '*.DS_Store' -x '*/evals/*'
zip -r ../rust-review.zip rust-review -x '*.DS_Store' -x '*/evals/*'
zip -r ../rust-port.zip rust-port -x '*.DS_Store' -x '*/evals/*'
Upload each under Customize > Skills. Code execution must be enabled first.
Reviewing existing code
Ask your agent to review a file, crate, or diff, for example "review src/parser.rs" or
"what would you change in this PR". The rust-review skill runs cargo fmt, clippy, and
the tests when a toolchain is available, then writes a report with three tiers: must fix,
should fix, and consider. Every finding gives a file:line location, the rule it breaks
with its source (an API Guidelines code such as C-GETTER, an Effective Rust item, a
Microsoft guideline, or a c
// HOW IT'S BUILT
// FILES
2 files shipped with this skill. Inline text is the catalog copy. The upstream link is the source repository.
skills/rust-best-practices/SKILL.md7.8 KBupstream ↗
--- name: rust-best-practices description: >- Write idiomatic, robust, maintainable Rust. Use this skill whenever you write, review, refactor, debug, or explain Rust code: new crates, modules, functions, structs, traits, error types, async code, unsafe or FFI code, Cargo.toml, tests, or rustdoc. Trigger on any mention of Rust, cargo, crates, .rs files, the borrow checker, lifetimes, traits, clippy, or rustfmt, even when the user does not ask for "best practices" or "idiomatic" code. Synthesized from the Google Rust Style Guide, the Rust API Guidelines, Effective Rust, Rust Design Patterns, and Microsoft's Pragmatic Rust Guidelines. --- # Rust best practices Distilled from five Rust style and design guides, with a digest of each in `references/`. Where they disagree, this file says which to follow and why. ## 1. Mindset - **Write Rust-shaped code.** Don't port C++, Java, C#, or Python constructs one-to-one. Model errors with `Result`, resources with ownership and `Drop`, polymorphism with traits and enums, and nullability with `Option`. Inheritance-flavored tricks (`Deref` to a "base" struct, `Manager`/`Factory` types, `throw_if_null` helpers) are smells. - **Make invalid states unrepresentable.** Push invariants into types: enums instead of bool flags and "must be X if Y" comments, newtypes for units and IDs, fallible constructors that validate once. Then the compiler enforces what a comment only requests. - **Application code is not library code.** Library code (anything with external users) follows the API-design rules below strictly. Application code should favor simplicity and directness: concrete types, `String` or `&str` rather than `impl Into<String>` parameters, `anyhow`-style errors, `Vec` return values, no speculative generality. - **Let the tools do the work.** rustfmt owns formatting, clippy owns idiom checks, the compiler owns memory safety. Spend your attention on design. ## 2. Before you hand back code Run these and fix everything they report: ```bash cargo fmt cargo clippy --all-targets --all-features -- -D warnings cargo test cargo doc --no-deps # libraries: catches broken doc links and missing docs ``` - Fix a lint rather than silencing it. When a lint is genuinely wrong for one item, use `#[expect(clippy::name, reason = "...")]` on the narrowest item. `expect` warns when the lint stops firing, so stale suppressions get cleaned up. Use `#[allow]` only in generated code or macro output. - Never put `#![deny(warnings)]` in source: new toolchains add warnings and break the build. Enforce warnings-as-errors in CI instead, with `cargo clippy -- -D warnings`. - Configure lints once in `Cargo.toml` (`[lints]` or `[workspace.lints]`), not with scattered crate attributes. If a project has none, suggest `lints/lints.toml` and `lints/clippy.toml` from https://github.com/morganlinton/BeautifulRust; the suppression lints in it need `rust-version` 1.81 or later. ## 3. Ownership and borrowing **Prefer unique ownership.** Reach for `Rc`/`Arc` only when shared ownership is part of the design, and for `RefCell`/`Mutex` only when interior mutability is. They are not failures, but they move checking from compile time to run time, so use them on purpose. **Don't clone to make the borrow checker stop complaining.** A clone that exists only to end a borrow produces a silent copy whose later changes are lost. Try these first, in roughly this order: 1. Extend a temporary with a named `let`, or shorten a borrow with a block. 2. Split a long expression into typed intermediates so the failing step is visible. 3. Move a field out of `&mut self` with `std::mem::take` (needs `Default`), `std::mem::replace`, or `Option::take` instead of cloning it. 4. Split a large struct into smaller ones so disjoint fields can be borrowed separately. The compiler tracks disjoint field borrows inside one function, but not across method calls. 5. Clone small, immutable data deliberately, and say so in a comment if it's not obvious. 6. Use indices into an owning `Vec`, or `Rc<RefCell<_>>` with `Weak` back-pointers, as a last resort. Avoid self-referential structs. ```rust // Move out of a &mut enum without cloning. fn a_to_b(e: &mut MyEnum) { if let MyEnum::A { name, x: 0 } = e { *e = MyEnum::B { name: std::mem::take(name) }; } } ``` **Accept the most general borrowed type.** `&str` not `&String`, `&[T]` not `&Vec<T>`, `&T` not `&Box<T>`, `Option<&T>` not `&Option<T>`. Deref coercion then lets callers pass owned values, borrows, or literals. Where you only read a path, string, or byte buffer, `impl AsRef<Path>` / `impl AsRef<str>` / `impl AsRef<[u8]>` is fine on parameters (never on struct fields; store `PathBuf` and `String`). Library code that only iterates should take `impl IntoIterator<Item = T>`; application code may simply take `&[T]`. **Take ownership only when you need it, and then take it by value.** If a function stores or consumes its argument, take `T`, not `&T` plus an internal `.clone()`. If it only reads, take `&T`; if it mutates in place, `&mut T`. Return multiple values as a tuple or struct, not through `&mut` out-parameters (reusing a caller-owned buffer, as `Read::read` does, is the exception). **Prefer owned data in structs.** A struct holding `&'a T` forces a lifetime onto every container. Owning a `String` or `Vec<u8>` is usually simpler and rarely the bottleneck. When a type does carry a lifetime, give it a descriptive name (`'src`, `'conn`); `'_` and `'a` are fine on simple functions. **Freeze after setup.** Build with `let mut`, then rebind `let data = data;` so later code cannot mutate it by accident. **Keep `Rc`, `Arc`, `Box`, and `RefCell` out of public signatures.** Take `&T`, `&mut T`, or `T` and let callers decide how to own things. A service that must be shared implements a cheap `Clone` by wrapping its state in `Arc<Inner>` internally. ## 4. Types and API design ### Naming | Item | Case | Notes | |---|---|---| | Types, traits, enum variants | `UpperCamelCase` | Acronyms are one word: `Uuid`, `HttpClient` | | Functions, methods, modules, locals | `snake_case` | | | Constants, statics | `SCREAMING_SNAKE_CASE` | | | Type parameters | short, from the main bound | `T`, `R: Read`, `W: Write` | | Lifetimes | short lowercase | descriptive when on a type | - No `get_` prefix on getters: `fn len(&self)`, `fn name(&self) -> &str`, `fn name_mut(&mut self)`. Use bare `get` only when there is one obvious thing to get (`Cell::get`). Related: `set_foo(T)`, `take_foo()`, `with_foo(|f| ..)` for closure access, and unsafe `_unchecked` siblings for checked accessors. - Conversion prefixes signal cost and ownership: `as_` (free, borrow to borrow), `to_` (expensive, borrow to owned or borrow to borrow), `into_` (consumes `self`). Put `mut` in type order: `as_mut_slice`, not `as_slice_mut`. - Constructors: `new` (primary), `with_capacity` / `new_with_foo` (variants), `try_new` (fallible), `from_foo` (conversion; pair important ones with a `From` impl). I/O resources use domain verbs: `File::open`, `TcpStream::connect`. - `iter` / `iter_mut` / `into_iter` return types named `Iter` / `IterMut` / `IntoIter`; `keys()` returns `Keys`. - Error types read verb-object-error: `ParseBoolError`, not `BoolParseError`. - Avoid weasel suffixes `Service`, `Manager`, `Factory`, `Helper`, `Util`. Name the thing it is (`Bookings`, `Dispatcher`, `FooBuilder`). Don't repeat the module name in the type (`foo::Id`, not `foo::FooId`). Avoid abbreviations an outsider wouldn't know. - If you implement `len()`, implement `is_empty()`. - Feature names are bare: `std`, `serde`, `alloc`, never `use-std` or `no-std`. ### Model the domain with types - **Newtypes** for semantic distinctions: `struct Miles(f64)` and `struct Kilometers(f64)` cannot be mixed, where a type alias can. Add `#[repr(transparent)]` when layout matters, and derive or forward the traits you need (`derive_moREADME.mdupstream ↗
Contents are not inlined in the catalog. Open the upstream file.
Plain-text copy, no login: /skill-bundles/morganlinton-beautifulrust-skills-rust-best-practices.md