code-rust
Use when editing or reviewing Rust files (*.rs) and the repository has no rust-coding-skill of its own.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when editing or reviewing Rust files (*.rs) and the repository has no rust-coding-skill of its own.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use when ingesting, refreshing, listing, searching, or deleting a local corpus with Blackbird code search and `gh blackbird search --fileset`.
Use when reaching for `gh blackbird` (Blackbird code search) for cross-repo lexical, symbol, or semantic search on GitHub — finding callers, ownership, or how systems work without cloning.
Use when creating a GitHub pull request, or when updating an existing PR's title or body so it matches what the code actually does.
Use when authoring or substantially editing a design doc, architecture doc, or subsystem explanation — the "here's what's there and why" companion to an ADR's terse decision record.
Use when creating a repo-tracked multi-agent planning PR for a large project, especially when phases, living docs, parallel agent prompts, and cross-PR coordination are needed.
Use when about to call a library, crate, or framework API you haven't verified, when a dependency's behavior is surprising, when training-data memory might be stale, or when investigating how a dependency actually behaves.
| name | code-rust |
| disabled | true |
| description | Use when editing or reviewing Rust files (*.rs) and the repository has no rust-coding-skill of its own. |
User-level fallback for Rust style and discipline. Apply when working in a
Rust repository that does not provide its own rust-coding-skill (or
equivalent). When a repo-local Rust skill exists, prefer it — it carries
project-specific conventions this skill cannot.
A starter template that mirrors this content with extension stubs for
project-specific rules lives at
copilot/templates/rust-coding-skill/SKILL.md in tclem/dotfiles. Use
the template when bootstrapping a new repo's Rust skill; use this skill
when no repo skill exists yet.
Use this when changing or reviewing Rust code in any repo that does not provide a narrower repo-local Rust skill.
Do not use this to override repository style guides, generated code conventions, or project-specific API patterns.
From most important to least important:
thiserror for typed error enums at module and library boundaries. Name
variants by what the caller should do (ShardNotFound, AuthRequired,
IndexCorrupted), not by where the error came from (DbError, ParseError,
HttpError).anyhow only at the binary boundary — top-level handlers, CLI entry
points, server commands. Never in library code.Box<dyn std::error::Error + Send + Sync> as a return type. It
erases type information, prevents matching on specific failures, and produces
opaque messages with no causal chain. Use a thiserror enum.unwrap() in production code. Use ? to propagate, let-else for
early returns, if let / match for branches, or expect("specific invariant") for truly infallible cases. unwrap() is for tests.is_none() / is_err() followed by unwrap() — use if let or match. The separate check is redundant and easy to desync.Options together: let (Some(a), Some(b)) = (x, y) else { return Err(...); };.panic! only for unrecoverable invariants where the whole application is
broken. Not for localized failures.#[error(transparent)] for wrapped errors that should pass through
unchanged.Option when absence indicates a non-recoverable
violation rather than an expected missing value.JoinHandle or document the lifecycle owner.tokio::task::spawn_blocking for short operations
(the blocking pool is bounded — don't saturate it with multi-second work).
Long-lived workers use a dedicated thread..await. Use channels (tokio::sync::mpsc /
oneshot) or restructure so the critical section finishes before the await.parking_lot::Mutex — common default; short critical sections that never
touch .await.std::sync::Mutex — use when you want poisoning for invariant-critical
state.tokio::sync::Mutex — last resort, only when the lock genuinely must be
held across .await.std::sync::LazyLock for lazy statics (stable since Rust 1.80). Do not
introduce once_cell::Lazy in new code.&self through. Immutable LazyLock<Regex> /
LazyLock<Config> are fine.stream::iter(...).buffer_unordered(N) over unbounded
join_all on dynamic collections.Box::pin locals;
don't #[allow] clippy::large_futures and don't raise thread stack size
as a workaround.Iterator,
Future, Display, Debug, Clone, Default, PartialEq, Hash,
Serialize/Deserialize, thiserror::Error) are fine. Real extension
seams where the consumer must be pluggable are also fine — document why.From/Into for contextual conversions. Prefer named methods:
to_record, into_parts, from_row, as_string. From/Into can't
carry context, can't fail expressively, and produce un-navigable call
sites where the target type is implicit.F: Fn(...) parameters. // Good
tracing::info!(shard_id = %id, path = %path.display(), "shard indexed");
// Bad
tracing::info!("shard {} indexed at {}", id, path.display());
error_span! over #[tracing::instrument]. The attribute
is easy to misuse: wrong level by default, captures all args, hides span
lifetime from readers.error_span!, not info_span!. Span level controls the
minimum filter at which the span is recorded. Under a warn/error
filter, an info_span is dropped, taking its fields and parent context
with it.span.enter() guard across .await. Use
.instrument(span) instead.assert_eq!(actual, expected) — actual first for readable diffs.unwrap() is fine in tests — not in production.serial_test only when truly necessary.#[ignore].All use statements at the top of the file. Never import items inline
within function bodies.
Prefer top-level imports over fully-qualified paths in expressions and match arms.
One use per line, group items from the same module with braces:
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
pub(crate) by default. Only pub when the API is truly public.#[expect(...)] over #[allow(...)] for lint suppression.
Apply on individual fields, not whole structs.let bindings.println!("{value:?}") not println!("{:?}", value)...Self::default() in production struct constructors. Explicitly
list all fields so adding a new field causes a compile error at every
construction site._ wildcards. When an enum gains a
variant, a wildcard arm silently swallows it. Exhaustive matches force
every call site to handle the new case.cargo tree; find unused
deps with cargo machete.cargo check, not cargo build.Comments explain why, never what. Engineers can read code. Decision test before writing any comment: "If I delete this, what is lost that can't be recovered by reading the code, types, names, and one navigation jump?" If the answer is "nothing," don't write it.
Anti-patterns: doc comments enumerating function body, block comments that paraphrase the next line, "this is used by X" pointers, flow-narrating bullets inside a function.