Use when the user sets up a new Cargo crate, edits Cargo.toml, adds dependencies, configures features (additive principle), tunes profiles, uses `[patch]` / `[replace]`, declares lints in `[lints]`, or wants the MSRV-aware resolver behavior (1.84). Prevents non-additive feature design, mixing dev with build dependencies, accidental release-profile overrides, and missing `rust-version` declarations. Covers: `cargo new` vs `cargo init` (lib / bin), Cargo.toml structure ([package], [dependencies], [dev-dependencies], [build-dependencies], target-specific deps), version requirements (caret / tilde / exact / wildcards), features (additive principle, `dep:` prefix, weak `?` deps, default features), profiles (dev / release / test / bench / custom), `[patch]` and `[replace]`, `[lints]` table (recent stabilization), MSRV-aware resolver (1.84), `package` metadata fields. Keywords: cargo, "Cargo.toml", "cargo new", "cargo init", "cargo add", dependencies, features, "default features", "no-default-features", "dep:" prefix, "weak feature", "?", profile, "release profile", "dev profile", "opt-level", LTO, "codegen-units", patch, replace, "[lints]", "rust-version", MSRV, "MSRV-aware resolver", "resolver 3", "version requirement", "caret", "tilde", "additive features", "feature unification".
license
MIT
compatibility
Designed for Claude Code. Requires Rust 1.85+, edition 2024.
metadata
{"author":"OpenAEC-Foundation","version":"1.0"}
rust-impl-cargo-project
The single-crate Cargo project setup skill: how to scaffold a crate, structure its Cargo.toml, declare dependencies safely, design features that obey the additive principle, tune profiles, override third-party code with [patch] / [replace], configure package-level lints via the [lints] table, and opt into the MSRV-aware resolver introduced in Rust 1.84.
Cross-references: [[rust-impl-workspaces]] (multi-crate layout with [workspace]), [[rust-core-toolchain]] (rustup channels, components, rust-toolchain.toml), [[rust-core-language-versions]] (which features stabilized in which release), [[rust-impl-build-scripts]] (build.rs, OUT_DIR, cargo:: directives).
When to use this skill
User runs cargo new or cargo init and asks lib vs bin, what edition, where files go.
User edits Cargo.toml and asks about [package], [dependencies], [dev-dependencies], [build-dependencies], or target-specific dependencies.
User asks about version requirements: caret vs tilde vs exact vs wildcard.
User designs a feature flag, hits a non-additive design, or asks about dep: / ? syntax.
User tunes [profile.release], defines a custom profile, or asks about LTO, opt-level, codegen-units, strip, panic.
User wants to override a transitive dependency via [patch.crates-io] or [replace].
User wants project-wide lint configuration via the [lints] table.
User wants cargo add to pick versions compatible with their MSRV (Rust 1.84+ resolver).
For multi-crate workspaces ([workspace], shared dependencies, default-members) see [[rust-impl-workspaces]]. For build.rs and the cargo:: directives see [[rust-impl-build-scripts]].
Decision tree: cargo new vs cargo init
Need a fresh directory?
YES -> cargo new <name> (creates ./<name>/)
NO -> cargo init [<path>] (initialises current dir or path)
Binary or library?
Binary (executable, main.rs) -> default, or `--bin` explicitly
Library (lib.rs, no main) -> `--lib`
Both (mixed lib + bin in one crate) -> create lib, then add src/main.rs
Need a different VCS than git?
git (default) | hg | pijul | fossil | none -> `--vcs <name>`
ALWAYS pass --lib when the crate is library-first. NEVER hand-edit Cargo.toml to switch crate type after cargo new; rerun with the right flag in a clean directory or add a [lib] / [[bin]] target explicitly.
cargo new in Rust 1.85+ writes edition = "2024" and uses resolver 3 by default. ALWAYS check the generated edition string when scaffolding inside an existing repo that pinned an older toolchain.
ALWAYS keep proptest, criterion, tokio-test, tempfile in [dev-dependencies]. NEVER put them in [dependencies]: they bloat downstream builds and pollute the public dependency graph.
ALWAYS keep bindgen, cc, pkg-config, cmake in [build-dependencies]. NEVER duplicate them in [dependencies] "just in case": that doubles compile time.
ALWAYS declare rust-version once the crate is published or shared. Without it the MSRV-aware resolver cannot help downstream users.
NEVER omit description and license on a crate destined for crates.io: publication will fail.
ALWAYS prefer the SPDX expression syntax ("MIT OR Apache-2.0") over license-file unless the license has no SPDX identifier.
Version requirements (semver)
Syntax
Meaning
Compatible range
Use when
"1.2.3"
caret, implicit
>=1.2.3, <2.0.0
default; allows minor + patch updates
"^1.2.3"
caret, explicit
>=1.2.3, <2.0.0
same as above, spelled out
"~1.2.3"
tilde
>=1.2.3, <1.3.0
pin minor, allow patch only
"=1.2.3"
exact
=1.2.3 only
reproducing a bug; library code should AVOID
"1.2"
caret on shorter version
>=1.2.0, <2.0.0
allow any patch + future minors
"1"
caret on major
>=1.0.0, <2.0.0
broadest stable range
"*"
wildcard
any version
NEVER in published crates
">=1.2, <1.5"
multiple
>=1.2.0, <1.5.0
excluding a known-bad range
ALWAYS use bare caret ("1.2.3") in library crates so consumers can dedupe transitive versions.
NEVER use "=x.y.z" in a published library: it forces every downstream graph to that exact version and breaks dedup.
NEVER use "*" outside throwaway scripts: it implies "any future major version is fine", which is never true.
Features: the additive principle
"A consequence of this is that features should be additive. That is, enabling a feature should not disable functionality, and it should usually be safe to enable any combination of features."
Source: Cargo features reference
This single rule drives every other feature-design decision.
[features]default = ["std"] # auto-enabled unless --no-default-featuresstd = [] # enables std supportserde = ["dep:serde"] # private dep, no implicit featureasync = ["dep:tokio", "serde?/derive"] # weak: only if serde is ALSO enabledfull = ["std", "serde", "async"] # aggregator feature
Syntax
Effect
Stabilised
feature = []
a bare feature flag, gates #[cfg(feature = "...")]
always
feature = ["other"]
enabling feature also enables other
always
optional = true on a dep
implicitly creates a feature of the same name
always
feature = ["dep:foo"]
enables optional dep foo WITHOUT creating an implicit feature
1.60
feature = ["foo?/bar"]
enables bar feature of foo ONLY if foo is enabled elsewhere
1.60
ALWAYS phrase a flag as "enables X". NEVER phrase it as "disables X" (e.g. an no_std feature is the wrong direction; use an opt-in std feature instead).
NEVER design two features that must not be enabled together. Feature unification means any consumer in the dep graph can flip either one on, and Cargo will refuse to fail loudly.
ALWAYS use dep:foo when an optional dependency name should NOT become a public feature flag. Otherwise users can --features foo directly, locking you into that name forever.
Profiles: compile-time knobs
Built-in profiles and their inheritance:
dev --(inherited by)--> test
release --(inherited by)--> bench
# Faster release builds, smaller binaries[profile.release]lto = "thin"codegen-units = 1strip = "symbols"# Custom profile inherits another[profile.release-debug]inherits = "release"debug = true# Speed up dependencies in dev builds[profile.dev.package."*"]opt-level = 2
ALWAYS set panic = "abort" only AFTER verifying no dependency relies on std::panic::catch_unwind. NEVER set it just to shrink binaries by reflex.
NEVER override panic, lto, or rpath in per-package overrides: only profile-wide settings accept those. Cargo errors out otherwise.
[patch] and [replace]: overriding sources
# Replace a registry dep with a local fork while debugging[patch.crates-io]serde = { git = "https://github.com/me/serde", branch = "fix-1234" }
# Or a path override[patch.crates-io]serde = { path = "../serde" }
ALWAYS prefer [patch] over the legacy [replace]. [patch] is workspace-aware and respects semver; [replace] is deprecated.
ALWAYS keep [patch] entries on a feature branch, not on main. NEVER ship a published crate that patches a registry dep: downstream cannot inherit [patch] from a dependency.
Levels: forbid, deny, warn, allow. Tool name comes from the part before :: in the lint name (unsafe_code -> lints.rust; clippy::enum_glob_use -> lints.clippy).
"These will only affect local development of the current package. Cargo only applies these to the current package and not to dependencies."
Source: Cargo manifest reference
priority lets a group (e.g. clippy::pedantic at priority = -1) be overridden by individual lints (default priority = 0).
ALWAYS use [lints] in Cargo.toml for new projects instead of #![deny(...)] at the crate root: the manifest form is grep-friendly, machine-editable, and inheritable across a workspace via lints.workspace = true (see [[rust-impl-workspaces]]).
NEVER set unsafe_code = "forbid" in a crate that contains unsafe blocks: forbid cannot be overridden by inner attributes, the build will fail.
MSRV-aware resolver (Rust 1.84+)
Three activation paths:
Cargo.toml: [package] resolver = "3" (requires the host toolchain to be >= 1.84).