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 guidance on workspace architecture, dependency management, testing strategies, and production patterns. Triggered when users ask about Rust workspaces, best practices, code organization, or scalable project structure.
/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
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.