agentleFS
vinhnxvinhnx/vtcode/.agents/skills/rust-skills/SKILL.md

rust-skills

Skill897 starsChanged 16 days agoApache-2.0View on GitHub

193 Rust coding rules across 14 categories. Use when writing, reviewing, or refactoring Rust code. Covers ownership, errors, async, API design, memory, performance, testing, and anti-patterns.

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When you need the reasoning behind a rule family — or a complete checklist for a task like publishing a crate or auditing an API — read the …

    line 296

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Rust Best Practices

Comprehensive guide for writing high-quality, idiomatic, and highly optimized Rust code. Contains 193 rules across 14 categories, prioritized by impact to guide LLMs in code generation and refactoring. Quick reference below; the reasoning behind each rule family lives in the per-source digests under references/ (adapted from BeautifulRust, MIT).

When to Apply

Reference these guidelines when:

  • Writing new Rust functions, structs, or modules
  • Implementing error handling or async code
  • Designing public APIs for libraries
  • Reviewing code for ownership/borrowing issues
  • Optimizing memory usage or reducing allocations
  • Tuning performance for hot paths
  • Refactoring existing Rust code

Rule Categories by Priority

PriorityCategoryImpactPrefixRules
1Ownership & BorrowingCRITICALown-14
2Error HandlingCRITICALerr-14
3Memory OptimizationCRITICALmem-15
4API DesignHIGHapi-17
5Async/AwaitHIGHasync-16
6Compiler OptimizationHIGHopt-12
7Naming ConventionsMEDIUMname-17
8Type SafetyMEDIUMtype-11
9TestingMEDIUMtest-15
10DocumentationMEDIUMdoc-11
11Performance PatternsMEDIUMperf-11
12Project StructureLOWproj-12
13Clippy & LintingLOWlint-12
14Anti-patternsREFERENCEanti-16

Quick Reference

1. Ownership & Borrowing (CRITICAL)

  • own-borrow-over-clone - Prefer &T borrowing over .clone()
  • own-slice-over-vec - Accept &[T] not &Vec<T>, &str not &String
  • own-cow-conditional - Use Cow<'a, T> only for real conditional ownership
  • own-arc-shared - Use Arc<T> for thread-safe shared ownership
  • own-rc-single-thread - Use Rc<T> for single-threaded sharing
  • own-refcell-interior - Use RefCell<T> for interior mutability (single-thread)
  • own-mutex-interior - Use Mutex<T> for interior mutability (multi-thread)
  • own-rwlock-readers - Use RwLock<T> when reads dominate writes
  • own-copy-small - Derive Copy for small, trivial types
  • own-clone-explicit - Make Clone explicit, avoid implicit copies
  • own-move-large - Move large data instead of cloning
  • own-lifetime-elision - Rely on lifetime elision when possible
  • own-borrow-counter-ladder - Fix borrow errors by moving data: mem::take, struct splitting, typed intermediates
  • own-drop-contract - Destructors never fail, panic, or block; bind guards to names

2. Error Handling (CRITICAL)

  • err-thiserror-lib - Use thiserror for library error types
  • err-anyhow-app - Use anyhow for application error handling
  • err-result-over-panic - Return Result, don't panic on expected errors
  • err-context-chain - Add context with .context() or .with_context()
  • err-no-unwrap-prod - Never use .unwrap() in production code
  • err-expect-bugs-only - Use .expect() only for programming errors
  • err-question-mark - Use ? operator for clean propagation
  • err-from-impl - Use #[from] for automatic error conversion
  • err-source-chain - Use #[source] to chain underlying errors
  • err-lowercase-msg - Error messages: lowercase, no trailing punctuation
  • err-doc-errors - Document errors with # Errors section
  • err-custom-type - Create custom error types, not Box<dyn Error>
  • err-panic-policy - Panics are not exceptions; poisoned locks are fatal; catch_unwind is last resort
  • err-app-lib-boundary - One app error type; libraries never expose anyhow; return consumed args in errors

3. Memory Optimization (CRITICAL)

  • mem-with-capacity - Use with_capacity() when size is known
  • mem-smallvec - Use SmallVec for usually-small collections
  • mem-arrayvec - Use ArrayVec for bounded-size collections
  • mem-box-large-variant - Box large enum variants to reduce type size
  • mem-boxed-slice - Use Box<[T]> instead of Vec<T> when fixed
  • mem-thinvec - Use ThinVec for often-empty vectors
  • mem-clone-from - Use clone_from() to reuse allocations
  • mem-reuse-collections - Reuse collections with clear() in loops
  • mem-avoid-format - Avoid format!() when string literals work
  • mem-write-over-format - Use write!() instead of format!()
  • mem-arena-allocator - Use arena allocators for batch allocations
  • mem-zero-copy - Use zero-copy patterns with slices and Bytes
  • mem-compact-string - Use CompactString for small string optimization
  • mem-smaller-integers - Use smallest integer type that fits
  • mem-assert-type-size - Assert hot type sizes to prevent regressions

4. API Design (HIGH)

  • api-builder-pattern - Use Builder pattern for complex construction
  • api-builder-must-use - Add #[must_use] to builder types
  • api-newtype-safety - Use newtypes for type-safe distinctions
  • api-typestate - Use typestate for compile-time state machines
  • api-sealed-trait - Seal traits to prevent external implementations
  • api-extension-trait - Use extension traits to add methods to foreign types
  • api-parse-dont-validate - Parse into validated types at boundaries
  • api-impl-into - Accept impl Into<T> for flexible string inputs
  • api-impl-asref - Accept impl AsRef<T> for borrowed inputs
  • api-must-use - Add #[must_use] to Result returning functions
  • api-non-exhaustive - Use #[non_exhaustive] for future-proof enums/structs
  • api-from-not-into - Implement From, not Into (auto-derived)
  • api-default-impl - Implement Default for sensible defaults
  • api-common-traits - Implement Debug, Clone, PartialEq eagerly
  • api-serde-optional - Gate Serialize/Deserialize behind feature flag
  • api-no-bool-params - No bool parameters in public signatures - enum or two methods
  • api-ffi-boundary - FFI: repr(C), same-side alloc/free, RAII pointer wrappers, foo-sys/bindgen

5. Async/Await (HIGH)

  • async-tokio-runtime - Use Tokio for production async runtime
  • async-no-lock-await - Never hold Mutex/RwLock across .await
  • async-spawn-blocking - Use spawn_blocking for CPU-intensive work
  • async-tokio-fs - Use tokio::fs not std::fs in async code
  • async-cancellation-token - Use CancellationToken for graceful shutdown
  • async-join-parallel - Use tokio::join! for parallel operations
  • async-try-join - Use tokio::try_join! for fallible parallel ops
  • async-select-racing - Use tokio::select! for racing/timeouts
  • async-bounded-channel - Use bounded channels for backpressure
  • async-mpsc-queue - Use mpsc for work queues
  • async-broadcast-pubsub - Use broadcast for pub/sub patterns
  • async-watch-latest - Use watch for latest-value sharing
  • async-oneshot-response - Use oneshot for request/response
  • async-joinset-structured - Use JoinSet for dynamic task groups
  • async-clone-before-await - Clone data before await, release locks
  • async-send-sync-assert - Pin Send/Sync with compile-time assert_send checks

6. Compiler Optimization (HIGH)

  • opt-inline-small - Use #[inline] for small hot functions
  • opt-inline-always-rare - Use #[inline(always)] sparingly
  • opt-inline-never-cold - Use #[inline(never)] for cold paths
  • opt-cold-unlikely - Use #[cold] for error/unlikely paths
  • opt-likely-hint - Use likely()/unlikely() for branch hints
  • opt-lto-release - Enable LTO in release builds
  • opt-codegen-units - Use codegen-units = 1 for max optimization
  • opt-pgo-profile - Use PGO for production builds
  • opt-target-cpu - Set target-cpu=native for local builds
  • opt-bounds-check - Use iterators to avoid bounds checks
  • opt-simd-portable - Use portable SIMD for data-parallel ops
  • opt-cache-friendly - Design cache-friendly data layouts (SoA)

7. Naming Conventions (MEDIUM)

  • name-types-camel - Use UpperCamelCase for types, traits, enums
  • name-variants-camel - Use UpperCamelCase for enum variants
  • name-funcs-snake - Use snake_case for functions, methods, modules
  • name-consts-screaming - Use SCREAMING_SNAKE_CASE for constants/statics
  • name-lifetime-short - Use short lowercase lifetimes: 'a, 'de, 'src
  • name-type-param-single - Use single uppercase for type params: T, E, K, V
  • name-as-free - as_ prefix: free reference conversion
  • name-to-expensive - to_ prefix: expensive conversion
  • name-into-ownership - into_ prefix: ownership transfer
  • name-no-get-prefix - No get_ prefix for simple getters
  • name-is-has-bool - Use is_, has_, can_ for boolean methods
  • name-iter-convention - Use iter/iter_mut/into_iter for iterators
  • name-iter-method - Name iterator methods consistently
  • name-iter-type-match - Iterator type names match method
  • name-acronym-word - Treat acronyms as words: Uuid not UUID
  • name-crate-no-rs - Crate names: no -rs suffix
  • name-weasel-types - No Service/Manager/Factory/Helper/Util; don't repeat the module name in the type

8. Type Safety (MEDIUM)

  • type-newtype-ids - Wrap IDs in newtypes: UserId(u64)
  • type-newtype-validated - Newtypes for validated data: Email, Url
  • type-enum-states - Use enums for mutually exclusive states
  • type-option-nullable - Use Option<T> for nullable values
  • type-result-fallible - Use Result<T, E> for fallible operations
  • type-phantom-marker - Use PhantomData<T> for type-level markers
  • type-never-diverge - Use ! type for functions that never return
  • type-generic-bounds - Add trait bounds only where needed
  • type-no-stringly - Avoid stringly-typed APIs, use enums/newtypes
  • type-repr-transparent - Use #[repr(transparent)] for FFI newtypes
  • type-strongest-std - Strongest std types: PathBuf, Duration, NonZeroU32 internal-only, bitflags vs enum

9. Testing (MEDIUM)

  • test-cfg-test-module - Use #[cfg(test)] mod tests { }
  • test-use-super - Use use super::*; in test modules
  • test-integration-dir - Put integration tests in tests/ directory
  • test-descriptive-names - Use descriptive test names
  • test-arrange-act-assert - Structure tests as arrange/act/assert
  • test-proptest-properties - Use proptest for property-based testing
  • test-mockall-mocking - Use mockall for trait mocking
  • test-mock-traits - Use traits for dependencies to enable mocking
  • test-fixture-raii - Use RAII pattern (Drop) for test cleanup
  • test-tokio-async - Use #[tokio::test] for async tests
  • test-should-panic - Use #[should_panic] for panic tests
  • test-criterion-bench - Use criterion for benchmarking
  • test-doctest-examples - Keep doc examples as executable tests
  • test-refactor-pin-behavior - Pin current behavior with tests before refactoring; list signature changes
  • test-miri-fuzz - Miri over unsafe; cargo fuzz untrusted-input parsers

10. Documentation (MEDIUM)

  • doc-all-public - Document all public items with ///
  • doc-module-inner - Use //! for module-level documentation
  • doc-examples-section - Include # Examples with runnable code
  • doc-errors-section - Include # Errors for fallible functions
  • doc-panics-section - Include # Panics for panicking functions
  • doc-safety-section - Include # Safety for unsafe functions
  • doc-question-mark - Use ? in examples, not .unwrap()
  • doc-hidden-setup - Use # prefix to hide example setup code
  • doc-intra-links - Use intra-doc links: [Vec]
  • doc-link-types - Link related types and functions in docs
  • doc-cargo-metadata - Fill Cargo.toml metadata

11. Performance Patterns (MEDIUM)

  • perf-iter-over-index - Prefer iterators over manual indexing
  • perf-iter-lazy - Keep iterators lazy, collect() only when needed
  • perf-collect-once - Don't collect() intermediate iterators
  • perf-entry-api - Use entry() API for map insert-or-update
  • perf-drain-reuse - Use drain() to reuse allocations
  • perf-extend-batch - Use extend() for batch insertions
  • perf-chain-avoid - Avoid chain() in hot loops
  • perf-collect-into - Use collect_into() for reusing containers
  • perf-black-box-bench - Use black_box() in benchmarks
  • perf-release-profile - Optimize release profile settings
  • perf-profile-first - Profile before optimizing

12. Project Structure (LOW)

  • proj-lib-main-split - Keep main.rs minimal, logic in lib.rs
  • proj-mod-by-feature - Organize modules by feature, not type
  • proj-flat-small - Keep small projects flat
  • proj-mod-rs-dir - Use mod.rs for multi-file modules
  • proj-pub-crate-internal - Use pub(crate) for internal APIs
  • proj-pub-super-parent - Use pub(super) for parent-only visibility
  • proj-pub-use-reexport - Use pub use for clean public API
  • proj-prelude-module - Create prelude module for common imports
  • proj-bin-dir - Put multiple binaries in src/bin/
  • proj-workspace-large - Use workspaces for large projects
  • proj-workspace-deps - Use workspace dependency inheritance
  • proj-semver-features - Semver is API: additive bare-named features, deprecate-then-remove, deliberate MSRV

13. Clippy & Linting (LOW)

  • lint-deny-correctness - #![deny(clippy::correctness)]
  • lint-warn-suspicious - #![warn(clippy::suspicious)]
  • lint-warn-style - #![warn(clippy::style)]
  • lint-warn-complexity - #![warn(clippy::complexity)]
  • lint-warn-perf - #![warn(clippy::perf)]
  • lint-pedantic-selective - Enable clippy::pedantic selectively
  • lint-missing-docs - #![warn(missing_docs)]
  • lint-unsafe-doc - #![warn(clippy::undocumented_unsafe_blocks)]
  • lint-cargo-metadata - #![warn(clippy::cargo)] for published crates
  • lint-rustfmt-check - Run cargo fmt --check in CI
  • lint-workspace-lints - Configure lints at workspace level
  • lint-expect-over-allow - #[expect(lint, reason)] over #[allow]; never #![deny(warnings)] in source

14. Anti-patterns (REFERENCE)

  • anti-unwrap-abuse - Don't use .unwrap() in production code
  • anti-expect-lazy - Don't use .expect() for recoverable errors
  • anti-clone-excessive - Don't clone when borrowing works
  • anti-lock-across-await - Don't hold locks across .await
  • anti-string-for-str - Don't accept &String when &str works
  • anti-vec-for-slice - Don't accept &Vec<T> when &[T] works
  • anti-index-over-iter - Don't use indexing when iterators work
  • anti-panic-expected - Don't panic on expected/recoverable errors
  • anti-empty-catch - Don't use empty if let Err(_) = ... blocks
  • anti-over-abstraction - Don't over-abstract with excessive generics
  • anti-premature-optimize - Don't optimize before profiling
  • anti-type-erasure - Don't use Box<dyn Trait> when impl Trait works
  • anti-format-hot-path - Don't use format!() in hot paths
  • anti-collect-intermediate - Don't collect() intermediate iterators
  • anti-stringly-typed - Don't use strings for structured data
  • anti-unsound-api - A safe API that can cause UB through safe calls is unsound

Deep Dive References

When you need the reasoning behind a rule family — or a complete checklist for a task like publishing a crate or auditing an API — read the per-source digests in references/ (adapted from BeautifulRust, MIT):

  • references/rust-api-guidelines.md - all 54 official C-codes with the full naming, interoperability, and predictability checklist
  • references/effective-rust.md - 35 items on choosing between alternatives: generics vs dyn, Result vs panic, iterators vs loops, borrow-checker tactics, dependency/CI policy
  • references/rust-design-patterns.md - idioms, patterns (builder, RAII, newtype, visitor, mem::take), and anti-patterns with code
  • references/microsoft-rust-guidelines.md - M-codes for teams: error struct design, panic/unsafe policy, workspace layout, agent-specific guidance
  • references/google-rust-style-guide.md - formatting, imports, module layout, accessor naming, and the application-vs-library distinction

Note on conflicting guidance: one habit from this skill's older lint rules is superseded — never put #![deny(warnings)] in source (new toolchains add warnings that break your build). Configure lint levels once in Cargo.toml ([lints.rust] / [workspace.lints]), override narrowly with #[expect(lint, reason)], and enforce warnings-as-errors in CI with cargo clippy -- -D warnings. See lint-expect-over-allow.


Recommended Cargo.toml Settings

[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true

[profile.bench]
inherits = "release"
debug = true
strip = false

[profile.dev]
opt-level = 0
debug = true

[profile.dev.package."*"]
opt-level = 3  # Optimize dependencies in dev

How to Use

This skill provides rule identifiers for quick reference. When generating or reviewing Rust code:

  1. Check relevant category based on task type
  2. Apply rules with matching prefix
  3. Prioritize CRITICAL > HIGH > MEDIUM > LOW
  4. Read rule files in rules/ for detailed examples

Rule Application by Task

TaskPrimary Categories
New functionown-, err-, name-
New struct/APIapi-, type-, doc-
Async codeasync-, own-
Error handlingerr-, api-
Memory optimizationmem-, own-, perf-
Performance tuningopt-, mem-, perf-
Code reviewanti-, lint-

PR Code Review

For automated PR bug review and fix loops, use the pr-code-review skill/agent. It ranks bugs critical/high/medium/low, eliminates false positives, applies KISS/DRY fixes (main logic only, skip tests), and re-reviews after every change. See AGENTS.md#pr-code-review-agent for full workflow.

/pr-code-review                    # review current uncommitted diff
/pr-code-review --branch main      # review branch diff against main
/pr-code-review --last-diff        # review the last committed diff

Sources

This skill synthesizes best practices from:

v1.1.0 additions adapted from BeautifulRust by Morgan Linton (MIT License, © 2025), which synthesizes the Google Rust Style Guide, the Rust API Guidelines, Effective Rust, Rust Design Patterns, and Microsoft's Pragmatic Rust Guidelines; full per-source digests are in references/.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.