rust-code-change

star 1

Apply this skill when Rust source, Cargo metadata, features, traits, errors, ownership, async runtime, unsafe code, tests, examples, or public crate APIs are created or changed.

0disoft By 0disoft schedule Updated 6/4/2026

mustflow_doc: skill.rust-code-change locale: en canonical: true revision: 4 lifecycle: mustflow-owned authority: procedure name: rust-code-change description: Apply this skill when Rust source, Cargo metadata, features, traits, errors, ownership, async runtime, unsafe code, tests, examples, benchmarks, release profiles, MSRV, toolchain declarations, standard-library APIs, or public crate APIs are created or changed. metadata: mustflow_schema: "1" mustflow_kind: procedure pack_id: mustflow.core skill_id: mustflow.core.rust-code-change command_intents: - changes_status - changes_diff_summary - lint - build - test_related - test - docs_validate_fast - mustflow_check


Rust Code Change

Purpose

Preserve Rust ownership, error, trait, feature, async runtime, unsafe, and public crate boundaries while making a focused change. A Rust change is successful only when it clarifies ownership and contracts, not when it merely silences the borrow checker.

Rust's compiler feedback can be especially useful for AI-assisted work because it rejects many invalid states with concrete errors. That benefit has a real cost: compile time, target-directory growth, native toolchain setup, release-profile slowness, and smoke-target selection must be managed instead of treated as incidental.

Use When

  • .rs, Cargo.toml, Cargo.lock, workspace config, feature flags, public exports, traits, error types, tests, examples, benches, FFI, async runtime, or unsafe code change.
  • The task touches ownership, borrowing, lifetimes, Clone, Arc, Mutex, unwrap, or public crate compatibility.
  • The task introduces or reviews Rust-version-gated APIs or language behavior such as let else, let chains, match if let guards, cfg_select!, assert_matches!, core::range, Vec::push_mut, HashMap::get_disjoint_mut, Option::take_if, LazyLock, OnceLock, workspace.lints, rust-version, Rust 2024 lints, or release-profile tuning.

Do Not Use When

  • Rust files are read-only context and no Rust surface changes.
  • A generated Rust file should be regenerated by a declared command rather than edited.

Required Inputs

  • Cargo.toml, workspace manifests, lockfile policy, toolchain config, rustfmt, clippy, feature flags, docs.rs metadata, optional dependencies, build profiles, target directory or cache policy, and CI hints.
  • Relevant src/lib.rs, src/main.rs, modules, public re-exports, tests, examples, and docs examples.
  • Existing error handling convention and async runtime.
  • Public crate status, minimum supported Rust version, feature support policy, and downstream compatibility expectations when available.
  • rust-version, edition, rust-toolchain.toml, CI toolchain matrix, target triples, Cargo resolver, workspace inheritance policy, and whether newer standard-library APIs require a raised MSRV.
  • Host and build-loop constraints: OS, shell, native toolchain prerequisites, VM or remote-builder use, release profile, LTO, workspace size, disk budget, and configured smoke or focused-check intents.
  • Configured verification intents.

Preconditions

  • Determine whether the change affects ownership flow, public API, feature gates, optional dependencies, error contract, async runtime, or unsafe invariants.
  • Read local patterns before adding traits, lifetimes, clones, locks, boxed errors, feature bounds, or Send + Sync + 'static constraints.
  • Treat clone, Arc<Mutex<_>>, explicit lifetimes, 'static, Box<dyn Error>, unwrap, feature changes, and unsafe as suspicious until their contract impact is justified.
  • Identify the intended edit-check-test loop before choosing a broad build. Treat whole-workspace checks, release builds, fat LTO, cross-compiles, and sanitizer-style runs as expensive evidence unless the command contract declares them as the normal focused path.
  • If a Rust release, "latest stable Rust", standard-library feature, Cargo behavior, edition behavior, lint default, or toolchain-support claim is written durably, use version-freshness-check and official Rust sources before relying on memory or pasted notes.

Allowed Edits

  • Prefer truthful ownership and borrowing over broad cloning.
  • Follow the crate's existing application-versus-library error convention.
  • Keep feature-gated code and public re-exports synchronized.
  • Touch unsafe code only with explicit invariants preserved in nearby comments.
  • Add feature, async, or unsafe verification notes when configured command intents are missing.
  • Keep build cache cleanup, remote compilation, VM escape hatches, and native toolchain repair as explicit environment or manual maintenance decisions. Do not hide them inside ordinary code fixes or verification.

Procedure

  1. Read Cargo metadata, features, optional dependencies, docs.rs metadata, toolchain config, build profiles, public exports, relevant modules, and tests.
  2. Classify the change as ownership, API, error, feature, async, unsafe, dependency, or test-only.
  3. Model the build loop before broad edits:
    • identify the smallest package, crate, feature set, smoke target, or test that covers the risk;
    • check whether target/ or an equivalent cache may grow enough to affect local disk budget;
    • treat cleaning build caches as a manual maintenance tradeoff because it can turn later compile checks into cold, expensive builds;
    • on Windows native targets, distinguish ordinary shells from developer toolchain shells when MSVC, SDK, linker, or environment setup is required;
    • treat VM builds, remote builders, release profiles, fat LTO, and whole-workspace checks as environment and verification choices that must be reported when they dominate iteration cost.
  4. Determine the Rust version contract before using newer syntax or standard-library APIs:
    • treat rust-version, edition, rust-toolchain.toml, CI matrix, docs.rs metadata, and downstream compatibility notes as the MSRV evidence ledger;
    • do not use 1.95+ APIs such as cfg_select!, match if let guards, or Vec::push_mut, or 1.96+ APIs such as assert_matches! and core::range, unless the declared MSRV and toolchain path support them;
    • keep experimental, nightly-only, target-specific, or edition-specific behavior behind explicit gates or fallbacks instead of calling it general Rust advice.
  5. Prefer flatter control flow when the MSRV supports it: use let else for early validation, let chains for related optional/result guards, and match if let guards for state-machine refinements. Remember that guard patterns do not satisfy match exhaustiveness; keep the fallback arm meaningful.
  6. In tests, prefer assert_matches! over assert!(matches!(...)) when the MSRV supports it and the failed value has useful Debug output. Import it explicitly from std or core; do not assume it is in the prelude.
  7. Resolve ownership problems in this order: identify the real owner, shrink borrow scopes, fix function signatures to accept references or slices when ownership is unnecessary, distinguish transfer from sharing, then consider clone or shared ownership only when the semantics require it.
  8. Before adding clone, verify it is a cheap handle clone such as Arc, Rc, or Bytes, a small intentional value clone, or a true independent ownership split. Reject large collection clones, loop clones, clone-then-borrow code, and whole-state clones made only to satisfy spawn.
  9. Before adding Arc<Mutex<_>>, verify multiple owners truly need shared mutable state. For read-mostly snapshots, prefer ownership-preserving choices such as Arc::make_mut, immutable swaps, or explicit reload boundaries. Keep critical sections short, document lock order when relevant, and do not hold a lock guard across .await, I/O, callbacks, or user code.
  10. Choose initialization primitives by input and failure semantics: use LazyLock for no-argument static lazy values that may poison permanently on panic, and OnceLock when boot-time or test-time code supplies the value or panic poisoning must not become the recovery policy.
  11. Avoid hidden allocation when cheaper type contracts fit: use Cow<'_, str> or borrowed slices for mostly-borrowed results, query HashMap<String, V> with &str when Borrow supports it, use Option::take, take_if, or as_slice for state transitions and 0-or-1 iteration, and use ControlFlow, try_for_each, or try_fold when visitor or iterator APIs need explicit short-circuiting.
  12. Treat collection and string capacity as part of performance correctness. Use with_capacity, reserve, spare_capacity_mut, or push_mut only when the safety and MSRV contract are clear; keep set_len inside a small proven unsafe boundary; avoid repeated String::insert or front insertion loops that create quadratic movement.
  13. Use explicit lifetimes only to describe real borrow relationships. Do not add 'static or T: 'static to public APIs merely because an internal task boundary requires it.
  14. Use concrete error enums for library APIs when callers need to classify failures. Keep Box<dyn Error> mostly to binaries, examples, tests, prototypes, or explicitly opaque error policies.
  15. Avoid unwrap, vague expect, and unbounded panic! in production paths. They are allowed only for tests, examples, startup policy, panic-boundary adapters, or invariants already proven by nearby code.
  16. Review public API shape before adding impl Trait, Deref, or trait/lifetime machinery:
  • argument-position impl Trait removes caller turbofish control and can be a public breaking change when converted from named generics;
  • return-position impl Trait hides one concrete type, so divergent iterator or future branches need an enum, boxed trait object, or different API boundary;
  • implement Deref only for pointer-like wrappers, not domain inheritance or method forwarding;
  • use GATs for borrowing iterator/view traits when they remove a real allocation or boxed lifetime escape, not as decorative complexity.
  1. If feature flags or Cargo workspace metadata change, treat default features, no-default builds, all-features builds, optional dependency implicit features, resolver behavior, target-specific dependencies, workspace.package, workspace.dependencies, workspace.lints, public re-exports, docs examples, and feature-gated trait impls as compatibility surfaces. Features should be additive, and resolver = "2" or a newer resolver decision must match the crate's edition/MSRV policy.
  2. Treat public re-exports, public dependency types, generic bounds, trait item sets, error enum variants, #[non_exhaustive], and MSRV as public API. Tightened bounds, added required trait methods, removed re-exports, changed error variants, or raised rust-version require compatibility review.
  3. Do not mix async runtimes. A Tokio crate should not casually gain async-std or runtime-specific APIs in library core. Do not call blocking I/O or CPU-heavy work in async paths without an established boundary such as async-native APIs, a blocking pool, or a dedicated worker.
  4. For async spawning, avoid leaking internal Send + Sync + 'static requirements into public APIs. Prefer owned task state, smaller spawn boundaries, local task structures, or caller-owned runtime decisions.
  5. Touch unsafe only when a safe design cannot express the required behavior. Every unsafe block needs a nearby SAFETY: explanation; every public unsafe fn needs # Safety docs. In Rust 2024 or when unsafe_op_in_unsafe_fn is enabled, unsafe operations inside unsafe fn still need explicit unsafe blocks. Keep unsafe scopes small and wrap them in safe abstractions only when callers have no hidden safety obligations.
  6. For FFI, keep Rust ABI types out of C boundaries. Use explicit ownership, #[repr(C)] where required, raw pointer plus length pairs, CStr/CString, RAII wrappers, null handling, panic boundaries, and documented thread-safety evidence before manual Send or Sync.
  7. Review release profiles when the task changes binary delivery, CLI startup, embedded, wasm, or performance behavior. Treat opt-level, LTO, panic, codegen-units, and strip as product tradeoffs that must be measured or reported, not decorative Cargo knobs.
  8. Calibrate performance claims. Do not claim Rust made a system faster from compile success, empty-database timings, warm-cache microbenchmarks, local-only runs, or debug versus release confusion. Require representative data size, concurrency, target hardware, profile, and measurement method before reporting speed claims.
  9. Choose configured verification intents that cover format, lint, build, tests, feature combinations, docs, public API, unsafe, FFI, smoke targets, package artifact, and release-profile risk when available.

Review Rejection Criteria

Reject or revise the patch when any of these appear without strong local justification:

  • New large clone() calls, clone-then-borrow code, loop clones, or state clones used only to appease ownership errors.
  • New Arc<Mutex<AppState>>-style shared bags, locks held across .await, or async I/O resources shared mainly by mutex.
  • New Rust 1.95+ or 1.96+ API usage without MSRV, rust-version, edition, toolchain, CI, or fallback evidence.
  • New LazyLock initialization for recoverable runtime configuration where permanent panic poisoning would be the wrong failure policy.
  • New spare_capacity_mut plus set_len without a narrow, proven initialization invariant.
  • New public impl Trait, Deref, GAT, workspace resolver, feature, or rust-version change without public API and compatibility review.
  • New public 'static, Send, or Sync bounds that exist only because an internal task was spawned.
  • New public Box<dyn Error> in a library where callers need typed failures.
  • New production unwrap or vague expect on I/O, parse, environment, network, FFI, lock, or user input paths.
  • New unbounded panic! paths, index assumptions, or unchecked slicing in production paths without a documented invariant or panic boundary.
  • Feature changes that remove APIs, change type meaning, rename features, expose internal optional dependency names, or fail default/no-default/all-features reasoning.
  • Public dependency types, re-exports, trait bounds, trait methods, or error enum variants changed without semver review.
  • Async runtime mixing, blocking I/O in async paths, or runtime ownership moved into a library core without a clear boundary.
  • Unsafe blocks without SAFETY: comments, unsafe functions without # Safety, undocumented manual Send/Sync, or FFI that exposes Rust layout types across C ABI.
  • Whole-workspace, release, or fat-LTO verification treated as the normal agent loop when a smaller configured smoke or related target should exist.
  • Performance superiority claims based on non-representative workloads, empty databases, local-only timings, or unspecified build profile.

Postconditions

  • Ownership changes are intentional, not compiler appeasement.
  • Rust-version-gated syntax, standard-library APIs, Cargo behavior, and lint assumptions match the declared MSRV or have explicit fallbacks.
  • Public API, features, optional dependencies, and error contracts are synchronized.
  • Async runtime ownership is preserved and blocking work is isolated.
  • Unsafe, unsafe_op_in_unsafe_fn, and FFI invariants are preserved or no unsafe code was touched.
  • Allocation, initialization, Cargo workspace, and release-profile choices are intentional and reported when they affect public or delivery behavior.
  • Build-loop cost, target/cache impact, smoke-target coverage, and native toolchain prerequisites are handled or reported.
  • Missing feature, semver, docs, unsafe, FFI, smoke, package, or performance verification is reported.

Verification

Use configured oneshot command intents when available:

  • lint
  • build
  • test_related
  • test
  • docs_validate_fast
  • mustflow_check

Report whether configured feature-combination, documentation, semver, Miri, sanitizer, smoke-target, package artifact, release-profile, and downstream-style verification exists when those surfaces change.

When configured intents exist for these risks, prefer coverage equivalent to:

  • formatting and linting
  • workspace checks and tests
  • focused smoke targets for the changed crate, command, API route, or engine invariant
  • default, no-default, all-features, and relevant feature combinations
  • doctests and docs build for public crates
  • public API or semver compatibility checks for published crates
  • Miri or sanitizer-style checks for unsafe, raw pointer, FFI, or manual concurrency primitives
  • representative benchmark or load checks when performance claims are introduced

Failure Handling

  • If borrow-checker fixes produce broad clones or locks, revisit ownership boundaries before proceeding.
  • If feature-gated code cannot be verified, report the specific unverified feature surface.
  • If public API compatibility cannot be verified, report the exact exported symbols, trait bounds, feature gates, or errors at risk.
  • If async runtime or blocking boundaries are unclear, stop that part and inspect the runtime ownership before editing further.
  • If unsafe invariants are unclear, stop that part and request or inspect stronger evidence.
  • If the build loop is too expensive, reduce the verification scope to the configured related or smoke intent when available, or report the missing command contract instead of running broad raw builds.
  • If host toolchain setup is missing, report the prerequisite rather than running global installer, repair, or shell-environment commands.
  • If performance claims lack representative evidence, downgrade or remove the claim.

Output Format

  • Boundary checked
  • Build-loop, cache, smoke target, and toolchain notes
  • Ownership, feature, async, or unsafe impact
  • Public API or error impact
  • Files changed
  • Command intents run
  • Skipped checks and reasons
  • Remaining Rust risk
Install via CLI
npx skills add https://github.com/0disoft/mustflow --skill rust-code-change
Repository Details
star Stars 1
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator