From ccfg-rust
This skill should be used when managing Cargo.toml configuration, workspace setup, dependency management, feature flags, publishing crates, or configuring build profiles in Rust projects.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ccfg-rust:cargo-conventionsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill defines comprehensive conventions for managing Rust projects with Cargo, covering
This skill defines comprehensive conventions for managing Rust projects with Cargo, covering Cargo.toml structure, workspace management, dependency practices, feature flags, build profiles, lints, and publishing.
Cargo.toml sections should follow a consistent order for readability.
# CORRECT: Standard section ordering
[package]
name = "my-crate"
version = "0.1.0"
edition = "2021"
rust-version = "1.75"
description = "A brief description"
license = "MIT OR Apache-2.0"
repository = "https://github.com/user/my-crate"
readme = "README.md"
keywords = ["keyword1", "keyword2"]
categories = ["category"]
[features]
default = ["json"]
json = ["dep:serde_json"]
xml = ["dep:quick-xml"]
[dependencies]
serde = { version = "1", features = ["derive"] }
thiserror = "2"
[dev-dependencies]
proptest = "1"
tokio = { version = "1", features = ["test-util", "macros"] }
[build-dependencies]
prost-build = "0.13"
[lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
[profile.release]
lto = true
# WRONG: Randomly ordered sections
[dev-dependencies]
proptest = "1"
[profile.release]
lto = true
[package]
name = "my-crate"
version = "0.1.0"
[dependencies]
serde = "1"
Always specify the edition. Set rust-version (MSRV) for libraries to communicate the minimum
supported Rust version.
# CORRECT: Edition and MSRV specified
[package]
name = "my-lib"
version = "0.1.0"
edition = "2021"
rust-version = "1.75"
# WRONG: Missing edition (defaults may change between Cargo versions)
[package]
name = "my-lib"
version = "0.1.0"
Since Rust 1.74, clippy lints should be configured in Cargo.toml using the [lints] table instead
of #![warn(...)] attributes in source files.
# CORRECT: Lints in Cargo.toml (modern approach)
[lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }
unwrap_used = "warn"
expect_used = "warn"
[lints.rust]
unsafe_code = "forbid"
missing_docs = "warn"
# WRONG: Using a separate clippy.toml for lint configuration
# clippy.toml files are for clippy-specific settings like msrv,
# not for lint levels
// WRONG: Lint attributes in source files (use Cargo.toml instead)
#![warn(clippy::all, clippy::pedantic)]
#![forbid(unsafe_code)]
In workspaces, define lints once at the workspace level and inherit them in member crates.
# CORRECT: Workspace root Cargo.toml
[workspace.lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }
unwrap_used = "warn"
# Member crate Cargo.toml
[lints]
workspace = true
# WRONG: Duplicating lint config in every member crate
# crate-a/Cargo.toml
[lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
# crate-b/Cargo.toml (same config repeated)
[lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
Use workspaces for multi-crate projects to share dependencies and build artifacts.
# CORRECT: Workspace root Cargo.toml
[workspace]
resolver = "2"
members = [
"crates/core",
"crates/api",
"crates/cli",
]
[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/user/project"
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
thiserror = "2"
anyhow = "1"
# Member crate: crates/core/Cargo.toml
[package]
name = "project-core"
version.workspace = true
edition.workspace = true
[dependencies]
serde.workspace = true
thiserror.workspace = true
# WRONG: Duplicating dependency versions across member crates
# crates/core/Cargo.toml
[dependencies]
serde = { version = "1", features = ["derive"] }
# crates/api/Cargo.toml
[dependencies]
serde = { version = "1", features = ["derive"] } # duplicated
For projects that are only a collection of crates with no root crate, use a virtual workspace.
# CORRECT: Virtual workspace (no [package] section)
[workspace]
resolver = "2"
members = [
"crates/*",
]
[workspace.dependencies]
# shared dependency catalog
# WRONG: Root crate that exists only to hold the workspace
[package]
name = "project-root"
version = "0.0.0"
publish = false
[workspace]
members = ["crates/*"]
Feature flags must only add functionality, never change or remove existing behavior. Enabling an additional feature should never break code that works without it.
# CORRECT: Features are purely additive
[features]
default = ["json"]
json = ["dep:serde", "dep:serde_json"]
xml = ["dep:quick-xml"]
tracing = ["dep:tracing"]
# WRONG: Mutually exclusive features
[features]
backend-postgres = ["dep:sqlx-postgres"]
backend-sqlite = ["dep:sqlx-sqlite"]
# These cannot be enabled together, violating the additive rule
Use the dep: syntax to enable optional dependencies without creating implicit feature names.
# CORRECT: dep: syntax (Rust 1.60+)
[features]
json = ["dep:serde", "dep:serde_json"]
[dependencies]
serde = { version = "1", optional = true }
serde_json = { version = "1", optional = true }
# WRONG: Implicit feature names from optional dependencies
[dependencies]
serde = { version = "1", optional = true }
serde_json = { version = "1", optional = true }
# This creates features named "serde" and "serde_json" implicitly
Document every feature flag in the crate-level documentation.
// CORRECT: Feature documentation in lib.rs
//! # Features
//!
//! - `json` (default): Enable JSON serialization via serde
//! - `xml`: Enable XML serialization via quick-xml
//! - `tracing`: Enable tracing instrumentation
Use semver-compatible version requirements. Prefer caret requirements for flexibility.
# CORRECT: Caret requirements (default, most flexible)
[dependencies]
serde = "1" # Equivalent to >=1.0.0, <2.0.0
tokio = "1.35" # Equivalent to >=1.35.0, <2.0.0
uuid = "1.7.0" # Equivalent to >=1.7.0, <2.0.0
# WRONG: Pinning exact versions (prevents deduplication)
[dependencies]
serde = "=1.0.195" # Exact pin prevents cargo from resolving conflicts
tokio = "=1.35.1" # Forces all consumers to use this exact version
Only enable the features you actually use.
# CORRECT: Only enable needed features
[dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "net", "macros"] }
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
# WRONG: Enabling all features when you only need a subset
[dependencies]
tokio = { version = "1", features = ["full"] }
reqwest = "0.12" # Pulls in default features including openssl
Dev dependencies are only used for tests, examples, and benchmarks. They should never appear in
[dependencies].
# CORRECT: Test-only dependencies in dev-dependencies
[dev-dependencies]
proptest = "1"
mockall = "0.13"
tempfile = "3"
criterion = { version = "0.5", features = ["html_reports"] }
# WRONG: Test frameworks in production dependencies
[dependencies]
proptest = "1" # Will be compiled into the production binary
Customize [profile.release] only in binary crates (services, CLIs). Libraries should not set
release profiles because the consuming binary controls the profile.
# CORRECT: Release profile in a binary crate
[profile.release]
lto = true
codegen-units = 1
strip = true
# WRONG: Release profile in a library crate
# The library does not control how it is compiled; the binary crate does
[package]
name = "my-library"
[profile.release]
lto = true # Has no effect when used as a dependency
# Service/CLI production profile
[profile.release]
lto = true # Link-Time Optimization: slower build, faster binary
codegen-units = 1 # Single codegen unit: slower build, better optimization
strip = true # Remove debug symbols: smaller binary
panic = "abort" # Abort on panic: smaller binary, no unwinding overhead
# Development profile tweaks (optional)
[profile.dev]
opt-level = 1 # Slight optimization for faster dev builds
Use custom profiles for specific scenarios:
# Fast release builds for CI (skip LTO for speed)
[profile.ci]
inherits = "release"
lto = false
codegen-units = 16
# Profiling build with debug symbols
[profile.profiling]
inherits = "release"
debug = true
strip = false
Before publishing to crates.io:
# CORRECT: All required metadata for publishing
[package]
name = "my-crate"
version = "1.0.0"
edition = "2021"
rust-version = "1.75"
description = "A concise description of what this crate does"
license = "MIT OR Apache-2.0"
repository = "https://github.com/user/my-crate"
documentation = "https://docs.rs/my-crate"
readme = "README.md"
keywords = ["keyword1", "keyword2"]
categories = ["development-tools"]
exclude = [
"tests/",
"benches/",
".github/",
"*.profraw",
]
# WRONG: Missing required metadata
[package]
name = "my-crate"
version = "1.0.0"
# Missing: description, license, repository
# crates.io will reject this or it will have poor discoverability
Use exclude to keep the published crate small:
# CORRECT: Exclude non-essential files
[package]
exclude = [
".github/",
".gitignore",
"tests/fixtures/large-data/",
"benches/",
"*.profraw",
"coverage/",
]
When publishing workspace members, each crate should have its own version even if they share
workspace.package.version. Use publish = false for internal-only crates.
# Internal crate not meant for crates.io
[package]
name = "project-internal"
version.workspace = true
publish = false
Libraries should gitignore Cargo.lock because consumers should resolve their own dependency
versions.
# .gitignore for a library
/target
Cargo.lock
Binary crates (services, CLIs) should commit Cargo.lock for reproducible builds.
# .gitignore for a service/CLI
/target
# Note: Cargo.lock is NOT in .gitignore
# CORRECT: Platform-specific dependencies
[target.'cfg(unix)'.dependencies]
nix = "0.29"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.58", features = ["Win32_Foundation"] }
# CORRECT: Dependencies only compiled when feature is enabled
[dependencies]
serde = { version = "1", optional = true, features = ["derive"] }
serde_json = { version = "1", optional = true }
[features]
json = ["dep:serde", "dep:serde_json"]
Use cargo-deny for comprehensive dependency auditing:
# deny.toml
[advisories]
vulnerability = "deny"
unmaintained = "warn"
yanked = "deny"
[licenses]
allow = [
"MIT",
"Apache-2.0",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Unicode-3.0",
]
confidence-threshold = 0.8
[bans]
multiple-versions = "warn"
wildcards = "deny"
deny = [
# Deny specific problematic crates
]
[sources]
unknown-registry = "deny"
unknown-git = "deny"
allow-git = []
# WRONG: No dependency auditing configured
# Vulnerable, unlicensed, or duplicate dependencies go unnoticed
# Check for outdated dependencies
cargo outdated
# Update within semver bounds
cargo update
# Check for security advisories
cargo audit
# Full dependency check
cargo deny check
Keep rustfmt.toml minimal. Most defaults are correct.
# CORRECT: Minimal, intentional rustfmt.toml
edition = "2021"
max_width = 100
use_field_init_shorthand = true
use_try_shorthand = true
# WRONG: Over-configured rustfmt that fights the defaults
edition = "2021"
max_width = 120
tab_spaces = 2
fn_args_layout = "Compressed"
imports_granularity = "Module"
group_imports = "StdExternalCrate"
reorder_imports = false
# Too many non-default settings creates friction for contributors
npx claudepluginhub jsamuelsen11/claude-config --plugin ccfg-rustScaffolds new Rust projects with best practices for Cargo.toml, linting (clippy, rustfmt), CI pipelines, and workspace organization.
Assists with Cargo.toml configuration, crate dependency management, project initialization, builds, tests, benchmarks, docs, troubleshooting, and best practices for Rust projects.
Enforces strict Rust standards including FAIL FAST error handling, workspace architecture, dependency management with version scripts, and patterns for code reviews, projects, and compilation fixes.