agentleFS
opencueopencue/cuecards/.agents/skills/claude-skill-rust/SKILL.md

Codex-skill-rust

Skill6 starsChanged 3 months agoMITView on GitHub

Guide for Rust development including code style, testing, building, and quality checks using cargo tools. Apply when working with Rust code, Cargo.toml, or running cargo commands.

  • Installs packages

We split this skill into the rules it gives an agent

25 rules. About 0 are common, 12 are distinctive, and 13 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈12

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 13

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Follow standard Rust conventions and idioms

    line 12
  2. Very specific:

    Use rustfmt for code formatting

    line 13
  3. Distinctive:

    Prefer descriptive variable and function names

    line 15
  4. Very specific:

    Prefer the modern <module_name>.rs style over the legacy mod.rs style for module files.

    line 19
  5. Very specific:

    Use cfg_attr to deny lints only in release builds (not debug or test)

    line 80
  6. Very specific:

    Document why each allow is necessary

    line 82
  7. Very specific:

    Avoid .unwrap() and .expect() - these cause panics and should not be used in production code.

    line 88
  8. Very specific:

    Use Result<T, E> return types with the ?

    line 90
  9. Distinctive:

    Prefer early returns for error conditions

    line 91
  10. Very specific:

    Libraries: Use thiserror to define custom error types with derive macros

    line 98
  11. Very specific:

    Applications: Use anyhow for convenient error handling with context

    line 99
  12. Very specific:

    Avoid println! and eprintln!

    line 143
  13. Very specific:

    After use statements before the first item

    line 178
  14. Distinctive:

    After code blocks (loops, conditionals, match arms) before subsequent statements

    line 179
  15. Distinctive:

    When struct or enum fields have documentation comments, add a blank line before each doc comment to visually separate the fields:

    line 183
  16. Distinctive:

    All items require rustdoc documentation comments.

    line 202
  17. Distinctive:

    Write unit tests in the same file as the code being tested

    line 276
  18. Very specific:

    Use integration tests in the tests/ directory for end-to-end functionality

    line 277
  19. Very specific:

    Run tests with cargo test

    line 278
  20. Distinctive:

    Document test functions with their purpose and what they verify

    line 280
  21. Distinctive:

    After completing changes to Rust code, run the following checks in order:

    line 284
  22. Distinctive:

    If any check fails, fix the issues before proceeding.

    line 295
  23. Very specific:

    Always add dependencies with default-features = false and explicitly specify the features you need.

    line 316
  24. Distinctive:

    When adding a new dependency:

    line 326
  25. Distinctive:

    Check the crate's documentation for available features

    line 328

≈ “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 Development Guide

Code Style

  • Follow standard Rust conventions and idioms
  • Use rustfmt for code formatting
  • Configure lints in lib.rs (see Crate-Level Lint Configuration below)
  • Prefer descriptive variable and function names

Module File Organization

Prefer the modern <module_name>.rs style over the legacy mod.rs style for module files.

Preferred (modern style):

src/
├── lib.rs
├── config.rs        # mod config
├── config/
│   └── parser.rs    # mod config::parser
├── network.rs       # mod network
└── network/
    ├── client.rs    # mod network::client
    └── server.rs    # mod network::server

Avoid (legacy style):

src/
├── lib.rs
├── config/
│   ├── mod.rs       # mod config
│   └── parser.rs    # mod config::parser
└── network/
    ├── mod.rs       # mod network
    ├── client.rs    # mod network::client
    └── server.rs    # mod network::server

Benefits of the modern style:

  • File names directly indicate the module name (no ambiguous mod.rs files)
  • Easier navigation in editors and file browsers
  • Clear correspondence between module path and file path
  • Supported since Rust 2018 edition

Crate-Level Lint Configuration

Define lint rules at the top of lib.rs (or main.rs for binaries) rather than via command-line flags. This ensures consistent enforcement and documents project standards.

#![deny(unsafe_code)]
#![cfg_attr(all(not(debug_assertions), not(test)), deny(clippy::all))]
#![cfg_attr(all(not(debug_assertions), not(test)), deny(clippy::pedantic))]
#![cfg_attr(all(not(debug_assertions), not(test)), deny(missing_docs))]
// Allow some pedantic lints that are too strict for this project
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::enum_variant_names)]
// Until 1.0.0, allow dead code and unused dependency warnings
#![allow(dead_code)]
#![allow(unused_crate_dependencies)]

Key principles:

  • Deny unsafe_code unless explicitly required
  • Use cfg_attr to deny lints only in release builds (not debug or test)
  • Allow specific pedantic lints that conflict with project conventions
  • Document why each allow is necessary

Important: These are good defaults for new crates. Do not override existing lint configurations - if a crate already specifies deny or allow for a rule, respect that choice.

Error Handling

Avoid .unwrap() and .expect() - these cause panics and should not be used in production code. Instead:

  • Use Result<T, E> return types with the ? operator for error propagation
  • Prefer early returns for error conditions
  • Handle errors explicitly at appropriate boundaries

Error Type Crates

Note: The following recommendations apply to std crates only. For no_std embedded targets, use custom error enums or thiserror with default-features = false.

  • Libraries: Use thiserror to define custom error types with derive macros
  • Applications: Use anyhow for convenient error handling with context

Example library error type with thiserror:

use thiserror::Error;

/// Errors that can occur during data processing.
#[derive(Debug, Error)]
pub enum ProcessError {
    /// The input data was empty.
    #[error("input data cannot be empty")]
    EmptyInput,

    /// Failed to parse the input data.
    #[error("failed to parse input: {0}")]
    ParseFailure(String),

    /// An I/O error occurred.
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),
}

Example application error handling with anyhow:

use anyhow::{Context, Result};

fn load_config(path: &Path) -> Result<Config> {
    let contents = std::fs::read_to_string(path)
        .context("failed to read config file")?;

    let config: Config = serde_json::from_str(&contents)
        .context("failed to parse config JSON")?;

    Ok(config)
}

Logging

Note: The following recommendations apply to std crates only. For no_std embedded targets, use defmt or platform-specific logging mechanisms.

Avoid println! and eprintln! outside of main application entry points. Use the log crate for structured logging instead.

use log::{debug, info, warn, error};

fn process_data(data: &[u8]) -> Result<(), ProcessError> {
    debug!("Processing {} bytes", data.len());

    if data.is_empty() {
        warn!("Received empty data buffer");
        return Err(ProcessError::EmptyInput);
    }

    info!("Data processed successfully");
    Ok(())
}

Log levels:

  • error! - Unrecoverable errors or failures
  • warn! - Unexpected conditions that are handled
  • info! - Significant events in normal operation
  • debug! - Detailed information for debugging
  • trace! - Very detailed tracing information

Applications should initialise a log implementation (e.g., env_logger, tracing-subscriber) in main().

Whitespace and Formatting

Maintain blank lines for readability:

  • Between module-level items (functions, structs, enums, traits, constants, impl blocks)
  • Between struct and enum members when they have doc comments
  • Between constant declarations
  • After use statements before the first item
  • After code blocks (loops, conditionals, match arms) before subsequent statements

Struct Field Formatting

When struct or enum fields have documentation comments, add a blank line before each doc comment to visually separate the fields:

pub struct Handle<T> {
    /// Index into the arena's resource vector.
    index: usize,

    /// Generation counter to detect stale handles after resource reuse.
    generation: u32,

    /// Type marker to prevent mixing handles of different resource types.
    _marker: PhantomData<T>,
}

For fields without documentation, blank lines are optional but may still aid readability for complex types.

Documentation

All items require rustdoc documentation comments.

For documenting the following item (functions, types, constants, fields):

/// Documentation for the item below.

For documenting the enclosing item (modules, crate root):

//! Documentation for the containing module.

Items requiring documentation include:

  • Functions and methods
  • Types (structs, enums, type aliases)
  • Traits and trait implementations
  • Constants and statics
  • Modules
  • Test functions
  • Struct and enum fields

Function Documentation

Function documentation must include:

  • Brief description of purpose
  • # Arguments section documenting each parameter
  • # Returns section documenting the return value
  • # Errors section if the function returns Result
  • # Panics section if the function can panic

Example:

/// Calculates the checksum for the given data buffer.
///
/// # Arguments
///
/// * `data` - The byte slice to calculate the checksum for.
/// * `seed` - Initial seed value for the checksum algorithm.
///
/// # Returns
///
/// The computed 32-bit checksum value.
///
/// # Errors
///
/// Returns `ChecksumError::EmptyBuffer` if `data` is empty.
fn calculate_checksum(data: &[u8], seed: u32) -> Result<u32, ChecksumError> {
    // ...
}

Constant Documentation

Constant documentation must include:

  • Description of the constant's purpose
  • Reference to specification, document, or section where applicable

Example:

/// Maximum transmission unit size in bytes.
///
/// Per RFC 894, Section 3 - Ethernet frames have a maximum payload of 1500 bytes.
const MTU_SIZE: usize = 1500;

Testing

  • Write unit tests in the same file as the code being tested
  • Use integration tests in the tests/ directory for end-to-end functionality
  • Run tests with cargo test
  • Aim for meaningful test coverage of core functionality
  • Document test functions with their purpose and what they verify

Build Verification

After completing changes to Rust code, run the following checks in order:

  1. Format Code: cargo fmt
  2. Format Check: cargo fmt --check
  3. Lint Check: cargo clippy -- -D warnings
  4. Tests: cargo test
  5. Release Build: cargo build --release
  6. Documentation: cargo doc --no-deps --document-private-items
  7. License Check: cargo deny check
  8. Security Audit: cargo audit

If any check fails, fix the issues before proceeding.

Security Tools

Projects should use these security tools:

  • cargo-deny: License and advisory checker. Install with cargo install cargo-deny. Configuration in deny.toml enforces permissive licenses (MIT, Apache-2.0, BSD) and denies copyleft licenses (GPL, LGPL, AGPL).
  • cargo-audit: Security vulnerability scanner. Install with cargo install cargo-audit. Scans dependencies against the RustSec Advisory Database.

Dependencies

When adding dependencies:

  • Choose well-maintained crates widely used in the Rust ecosystem
  • For workspaces, add shared dependencies to [workspace.dependencies] in root Cargo.toml
  • Justify each dependency with a clear use case
  • Disable default features and explicitly enable only required features

Minimising Dependencies

Always add dependencies with default-features = false and explicitly specify the features you need. This reduces compile times and binary size by avoiding unnecessary transitive dependencies.

# Prefer this:
serde = { version = "1.0", default-features = false, features = ["derive"] }

# Avoid this:
serde = "1.0"

When adding a new dependency:

  1. Check the crate's documentation for available features
  2. Identify the minimum set of features required for your use case
  3. Add with default-features = false
  4. Explicitly list only the features you need

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.

Reviews can't be read right now.

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.