This skill should be used when the user asks about "rust workspace", "rust best practices", "cargo workspace setup", "rust code organization", "rust dependency management", "rust testing strategy", "rust project", "scalable rust", "rust CI setup", or needs guidance on senior-level Rust development patterns, workspace design, code organization strategies, or production-ready Rust architectures.
Provides senior-level Rust development guidance for workspaces, architecture, dependencies, testing, and quality.
/plugin marketplace add clementwalter/rookie-marketplace/plugin install rust-dev@rookie-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Battle-tested patterns for Rust workspace architecture, code organization, dependencies, and testing that scale from prototype to production.
All coding work MUST happen in git worktrees. Before making any code changes:
git worktree add ~/.claude/worktrees/$(basename $(pwd))/<task> -b feat/<task>/merge to consolidate changes back to mainNever edit files directly in the main worktree.
Before completing ANY Rust task, you MUST:
cargo test --workspacetrunk checkIf trunk has formatting issues, run trunk fmt to auto-fix.
Use a Rust workspace when you have:
Canonical workspace structure:
repo/
Cargo.toml # workspace root
crates/
core/ # pure domain logic (no IO)
storage/ # DB, filesystem, etc.
api/ # HTTP/GRPC handlers, DTOs
cli/ # binary
tools/ # optional: internal binaries (codegen, migration, etc.)
tests/ # optional: black-box integration tests
Layered architecture:
Critical rule: If core imports tokio, reqwest, or sqlx, you've already lost the separation.
Too many crates is busywork. Start with 2–5 max.
Split only when:
In root Cargo.toml, use workspace dependencies to keep versions aligned:
[workspace]
members = ["crates/*"]
resolver = "2"
[workspace.dependencies]
anyhow = "*" # use latest
thiserror = "*" # use latest
serde = { version = "*", features = ["derive"] } # use latest
tokio = { version = "*", features = ["macros", "rt-multi-thread"] } # use latest
In crate Cargo.toml:
[dependencies]
serde = { workspace = true }
This reduces version drift and security churn.
Pattern for optional dependencies:
[dependencies]
sqlx = { workspace = true, optional = true }
[features]
db = ["dep:sqlx"]
rust-toolchain.tomlOrganize by capability / domain, not by "models/handlers/utils" spaghetti.
Good organization:
core/
src/
lib.rs
payment/
mod.rs
validation.rs
pricing.rs
user/
mod.rs
id.rs
rules.rs
Avoid:
models.rs
handlers.rs
utils.rs
pub(crate) by defaultlib.rsmod payment;
pub use payment::{Payment, PaymentError};
If everything is pub you've created an accidental framework.
Preludes tend to hide dependencies and make code review harder. Prefer explicit imports.
Common approach:
thiserror for typed errorsanyhow at the top levelDon't leak anyhow::Error across library boundaries unless you explicitly want "opaque".
If you can keep core synchronous and pure, you gain:
Every dependency adds:
Prefer "boring" crates with strong maintenance.
cargo-deny + cargo-auditMake dependency issues visible early (licenses, advisories, duplicate versions).
unwrap() in LibrariesIn binaries/tests it's fine (especially in test scaffolding). In libraries, return errors with context.
Think "pyramid":
mod tests {} in the same file for private accessUse crates/<crate>/tests/*.rs for API-level tests.
If you have a service:
proptest for invariants ("decode(encode(x)) == x")cargo-fuzz for parsers/decoders/inputs from outsideDoctests enforce that examples compile and keep your public API honest.
println! - Use Tracing InsteadNEVER use println!, eprintln!, or dbg! for output. Always use the tracing crate:
use tracing::{debug, info, warn, error, trace};
// Good - structured logging
info!("Processing request for user {user_id}");
debug!("Cache hit: {key}");
warn!("Retry attempt {attempt} of {max_retries}");
error!("Failed to connect: {err}");
// Bad - never do this
println!("Processing request for user {}", user_id);
dbg!(value);
Why:
test-log for TestsAlways use test_log::test attribute for tests to capture tracing output:
use test_log::test;
#[test]
fn test_something() {
info!("This will be visible when test fails or with --nocapture");
assert!(true);
}
#[test(tokio::test)]
async fn test_async_something() {
debug!("Async test with tracing");
}
Add to Cargo.toml (use latest versions):
[dev-dependencies]
test-log = { version = "*", features = ["trace"] } # use latest
tracing-subscriber = { version = "*", features = ["env-filter"] } # use latest
Run tests with visible logs: RUST_LOG=debug cargo test -- --nocapture
clippy::uninlined_format_args)Always use variables directly in format strings instead of passing them as arguments:
// Good - variable inlined
let name = "world";
info!("Hello, {name}!");
format!("Value: {value}, Count: {count}")
// Bad - uninlined arguments
info!("Hello, {}!", name);
format!("Value: {}, Count: {}", value, count)
This improves readability and reduces potential argument ordering mistakes.
cargo fmt --check
cargo clippy --all-targets --all-features -D warnings
cargo test --workspace --all-features
Additional gates:
cargo deny / cargo auditcargo llvm-cov for coverage, but don't worship %resolver = "2" and avoid unnecessary default featuresOne-way dependencies:
core → (nothing)adapters → coreapp → adapters + corebin → appVisibility:
IO placement:
coreTest distribution:
Tooling:
CLI: Thin binary → lib (for testability)
Services: Separate protocol definitions; feature-flag transport layers
ZK/crypto: Isolate no_std core; separate proving/verification crates
WASM: Separate bindings; platform-agnostic core
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.