agentsclimarketplace

Rust strict

Skill 0xMassi/claude-skills/rust-strict

Twelve Claude Code skills enforcing strict code quality, security, and modern language patterns across TypeScript, Rust, Swift, Go, JavaScript, and PostgreSQL.

Install
npx -y skills add 0xMassi/claude-skills --skill rust-strict

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 5 stars5 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

Rust security, strictness, and vulnerability prevention rules. Use when writing, reviewing, or auditing Rust code. Complements rust-skills (179 general rules) with security-focused rules: unsafe audit, unwrap/expect bans, error handling hierarchy, secret handling, concurrency safety, input validation for Tauri commands, and release profile hardening. Derived from production Rust projects.

SKILL.md

11.9 KB, as published. Nobody here has run it

Rust Strict Standard

Security and strictness rules complementing the existing rust-skills (179 rules). These rules are derived from 5 production Rust projects.

CRITICAL: Workspace Lint Configuration

Every Rust project must configure workspace lints. Baseline:

# Cargo.toml (workspace root)
[workspace.lints.rust]
unsafe_code = "deny"              # No unsafe in production code
unused_qualifications = "deny"

[workspace.lints.clippy]
unwrap_used = "deny"              # Force proper error handling
expect_used = "deny"              # Same: use ? or ok_or_else()

Per-crate opt-in:

# crates/my-crate/Cargo.toml
[lints]
workspace = true

Exceptions (feature-gated, never blanket)

// FFI crate only: deny everywhere else
#![cfg_attr(feature = "local-llm", allow(unsafe_code))]

// Static initialization (regex, lazy): this is the ONLY acceptable expect()
static PATTERN: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"...").expect("regex must compile") // Bug if this fails
});

CRITICAL: Error Handling Hierarchy

Rule: Library crates use thiserror, app crates use anyhow

// Library crate: structured errors
#[derive(Debug, thiserror::Error)]
pub enum GatewayError {
    #[error("authentication required")]
    AuthRequired,

    #[error("rate limited: retry after {retry_after_ms}ms")]
    RateLimited { retry_after_ms: u64 },

    #[error("payload too large: {size} exceeds {max} bytes")]
    PayloadTooLarge { size: usize, max: usize },
}

impl GatewayError {
    pub fn status_code(&self) -> StatusCode { /* match self */ }
    pub fn is_retryable(&self) -> bool { matches!(self, Self::RateLimited { .. }) }
}

// App crate: flexible propagation
fn main() -> anyhow::Result<()> {
    let config = load_config().context("failed to load configuration")?;
    Ok(())
}

Rule: Tauri commands return Result<T, String>

#[tauri::command]
pub async fn my_command(
    state: tauri::State<'_, AppState>,
) -> Result<ResponseData, String> {
    let data = do_work().map_err(|e| format!("operation failed: {e}"))?;
    Ok(data)
}

Tauri serializes errors as strings: this is the framework constraint, not a hack.

Rule: Never Box<dyn Error>: use domain-specific enums

// BAD
fn process() -> Result<(), Box<dyn std::error::Error>> { ... }

// GOOD
fn process() -> Result<(), GatewayError> { ... }

CRITICAL: Unsafe Audit Rules

When unsafe is acceptable (with mandatory SAFETY comment)

// 1. SIMD intrinsics with runtime feature detection
#[target_feature(enable = "avx2,fma")]
unsafe fn cosine_similarity_avx2(a: &[f32], b: &[f32]) -> f64 {
    // SAFETY: AVX2 feature verified by caller via is_x86_feature_detected!
    let va = unsafe { _mm256_loadu_ps(a_ptr.add(offset)) };
    // offset < chunks*8 <= n: bounds checked by loop structure
}

// 2. Test-only env manipulation (with guard lock)
#[cfg(test)]
fn test_env_var() {
    let _guard = env_lock(); // Prevents test race conditions
    // SAFETY: env_lock serializes all env var access in tests
    unsafe { std::env::set_var("KEY", "value") };
}

When unsafe is NEVER acceptable

  • String/buffer manipulation (use safe APIs)
  • Pointer arithmetic without bounds proof
  • transmute (almost always wrong: use From/Into)
  • Implementing Send/Sync manually (unless wrapping C FFI)
  • unsafe impl without audited invariants

HIGH: Concurrency Safety

Rule: Never hold RwLock/Mutex across .await

// BAD: deadlock risk
let mut data = state.data.write().await;
data.insert(key, value);
let json = serde_json::to_string(&*data)?;
tokio::fs::write(path, json).await; // STILL LOCKED

// GOOD: clone, drop, then write
let json = {
    let mut data = state.data.write().await;
    data.insert(key, value);
    serde_json::to_string(&*data)?
}; // Lock dropped
tokio::fs::write(path, json).await;

Rule: Never hold RwLock across disk I/O

// BAD
let mut cookies = state.cookies.write().await;
cookies.insert(name, result);
std::fs::write(&path, serde_json::to_string(&*cookies)?); // SYNC I/O WHILE LOCKED

// GOOD
let json = {
    let mut cookies = state.cookies.write().await;
    cookies.insert(name, result);
    serde_json::to_string(&*cookies)?
};
tokio::fs::write(&path, json).await;

Rule: Use atomics for flags/counters, RwLock for data

pub struct AppState {
    // Atomics: lock-free for simple state
    pub is_running: AtomicBool,
    pub connection_count: AtomicUsize,

    // RwLock: for collections and complex data
    pub sessions: RwLock<HashMap<String, Session>>,

    // Watch channel: for shutdown signaling
    pub shutdown: watch::Sender<bool>,
}

Rule: BoundedMap for all caches (prevent memory leaks)

// BAD: unbounded HashMap cache
let cache: HashMap<String, CachedValue> = HashMap::new();

// GOOD: bounded with capacity + TTL
let cache = BoundedMap::new(1000, Duration::from_secs(300));

HIGH: Secret Handling

Rule: Secrets in Keychain, never plain files

// macOS: system `security` CLI (subprocess, not FFI)
#[cfg(target_os = "macos")]
fn keychain_get(account: &str) -> Result<Option<String>, String> {
    let output = Command::new("security")
        .args(["find-generic-password", "-s", "AppName", "-a", account, "-w"])
        .output()
        .map_err(|e| format!("keychain read failed: {e}"))?;
    // ...
}

// Fallback: Tauri plugin-store (encrypted)
#[cfg(not(target_os = "macos"))]
fn save_fallback(app: &AppHandle, name: &str, value: &str) -> Result<(), String> { ... }

Rule: Use obfstr!() for hardcoded strings in binary

// BAD: visible in binary strings
let api_url = "https://api.internal.example.com/v2";

// GOOD: obfuscated at compile time
let api_url = obfstr::obfstr!("https://api.internal.example.com/v2");

Rule: Validate empty strings on secret storage

pub fn save_secret(name: &str, value: &str) -> Result<(), String> {
    let trimmed = value.trim();
    if trimmed.is_empty() {
        return Err("Secret value cannot be empty".to_string());
    }
    // Proceed with trimmed value
}

HIGH: Input Validation (Tauri Commands)

Rule: Enum-constrain all command inputs

// BAD: arbitrary string input
#[tauri::command]
fn spawn_agent(agent: String) -> Result<(), String> {
    Command::new(&agent).spawn(); // COMMAND INJECTION
}

// GOOD: enum-constrained
#[derive(Debug, Clone, Deserialize)]
pub enum AgentType { Claude, Codex, Opencode }

#[tauri::command]
fn spawn_agent(agent: AgentType) -> Result<(), String> {
    let binary = match agent {
        AgentType::Claude => "claude",
        AgentType::Codex => "codex",
        AgentType::Opencode => "opencode",
    };
    // Safe: only known values
}

Rule: Use tempfile crate for temp files

// BAD: predictable path, symlink attacks
std::fs::write("/tmp/prompt.txt", prompt)?;

// GOOD: unpredictable, auto-cleanup
let mut tmp = tempfile::NamedTempFile::new()
    .map_err(|e| format!("temp file failed: {e}"))?;
writeln!(tmp, "{}", prompt)?;
let path = tmp.path().to_string_lossy().to_string();

MEDIUM: Dependency Rules

Rule: Explicit feature control

# BAD: pulls in everything
reqwest = "0.12"

# GOOD: only what you need
reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] }

Rule: rustls-tls over native-tls

Pure Rust TLS stack: no OpenSSL dependency, auditable, consistent behavior.

Rule: Workspace dependency inheritance

# Workspace Cargo.toml
[workspace.dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }

# Crate Cargo.toml
[dependencies]
tokio = { workspace = true }
serde = { workspace = true }

HIGH: Type Safety Patterns

Rule: Newtype for IDs and units

// BAD: any UUID can be passed where any ID is expected
pub fn ban_user(uid: Uuid, by: Uuid) { ... }

// GOOD: type system rejects swapped arguments
pub struct UserId(Uuid);
pub struct AdminId(Uuid);

pub fn ban_user(uid: UserId, by: AdminId) { ... }

Same pattern for units: Bytes(u64), Millis(u64), RetryCount(u32).

Rule: #[must_use] on results that should not be silently dropped

#[must_use = "builder is incomplete until .build() is called"]
pub struct RequestBuilder { ... }

#[must_use]
pub fn try_acquire(&self) -> Option<Lease> { ... }

Result<T, E> already has #[must_use]. Add it to builders, locks, and validation outcomes.

Rule: Explicit overflow handling on arithmetic

// BAD: wraps silently in release mode
let next = current + delta;

// GOOD: pick the semantic you mean
let next = current.checked_add(delta).ok_or(Error::Overflow)?;  // fail
let next = current.saturating_add(delta);                        // clamp
let next = current.wrapping_add(delta);                          // wrap (rare, document why)

Default to checked_* for anything user-influenced (sizes, counts, indices).

HIGH: Edition 2024

Edition 2024 ships with Rust 1.85 (Feb 2025). Current stable is 1.95.0. New crates start at edition 2024 with current stable. Migration changes that affect strict-mode rules:

Rule: Wrap external symbols in unsafe extern "C" blocks

// BAD: edition 2024 hard error
extern "C" { fn external_fn(); }

// GOOD
unsafe extern "C" {
    fn external_fn();
}

Forces the FFI declaration site to acknowledge unsafety.

Rule: unsafe_op_in_unsafe_fn is warn-by-default

Inside unsafe fn, every individual unsafe operation now needs its own unsafe { ... } block. This makes the audit surface explicit, do not bypass with #[allow].

Rule: Capture lifetimes explicitly with use<...> on RPIT

// Edition 2024: opaque return types capture all generic params by default
fn parse(s: &str) -> impl Iterator<Item = &str> + use<'_> { ... }

The use<> syntax is the escape hatch for the new capture rules. Reach for it when the inferred capture set is wrong.

Rule: gen is a reserved keyword

If you have variables, functions, or modules named gen, rename them before migrating.

Rule: tracing for structured logs, not log or env_logger

use tracing::{info, instrument, warn};

#[instrument(skip(state), fields(user_id = %req.user_id))]
async fn handler(state: AppState, req: Request) -> Result<Response, Error> {
    info!("processing request");
    ...
}

tracing is the de-facto standard. Pair with tracing-subscriber for output and tracing-opentelemetry for distributed tracing.

MEDIUM: Release Profile

Desktop apps (smallest binary)

[profile.release]
strip = true
lto = true            # Full LTO
codegen-units = 1
opt-level = 3
panic = "abort"        # No unwinding

Server/gateway (balanced)

[profile.release]
strip = true
lto = "thin"          # Faster compile than full LTO
codegen-units = 1

Dev profile (fast compile)

[profile.dev.package."*"]
opt-level = 3         # Optimize deps in dev (faster runtime)

Vulnerability Checklist

  • No unsafe blocks without SAFETY comments and justification
  • No .unwrap() or .expect() in production (deny via lint)
  • No string-constructed commands (enum-constrained)
  • No predictable temp file paths (use tempfile crate)
  • No secrets in source code (use env vars, Keychain, obfstr)
  • No unbounded caches (use BoundedMap with capacity + TTL)
  • No locks held across .await or disk I/O
  • CSP configured in tauri.conf.json (for Tauri apps)
  • cargo audit passes with no advisories
  • cargo clippy -- -D warnings clean

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.