Migrate Core Code to Submodules
tinyhumansai/openhuman
Plans and carries out moving non-host-specific code and its tests from the OpenHuman core into vendored tiny submodule libraries, then releases the submodule and re-pins the host.
Rust idioms: ownership and borrow checker patterns, error handling with thiserror/anyhow, Tokio async concurrency, lifetime management, and Clippy pedantic compliance.
$ npx skills add irahardianto/awesome-agv --skill rust-idioms -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install irahardianto/awesome-agv rust-idioms --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/rust-idioms .claude/skills/rust-idioms && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "rust-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/rust-idioms into .claude/skills/rust-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "rust-idioms", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/rust-idiomsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add irahardianto/awesome-agv --skill rust-idioms -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install irahardianto/awesome-agv rust-idioms --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/rust-idioms .agents/skills/rust-idioms && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "rust-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/rust-idioms into .agents/skills/rust-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "rust-idioms", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add irahardianto/awesome-agv --skill rust-idioms -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install irahardianto/awesome-agv rust-idioms --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/rust-idioms .cursor/skills/rust-idioms && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "rust-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/rust-idioms into .cursor/skills/rust-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "rust-idioms", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/irahardianto/awesome-agv.git --path .agents/skills/rust-idioms--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add irahardianto/awesome-agv --skill rust-idioms -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install irahardianto/awesome-agv rust-idioms --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/rust-idioms .gemini/skills/rust-idioms && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "rust-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/rust-idioms into .gemini/skills/rust-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "rust-idioms", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install irahardianto/awesome-agv rust-idiomsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add irahardianto/awesome-agv --skill rust-idioms -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/rust-idioms .github/skills/rust-idioms && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "rust-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/rust-idioms into .github/skills/rust-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "rust-idioms", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add irahardianto/awesome-agv --skill rust-idioms -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install irahardianto/awesome-agv rust-idioms --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/rust-idioms .opencode/skills/rust-idioms && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "rust-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/rust-idioms into .opencode/skills/rust-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "rust-idioms", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
rust-idiomsRust idioms: ownership and borrow checker patterns, error handling with thiserror/anyhow, Tokio async concurrency, lifetime management, and Clippy pedantic compliance.
Rust Idioms is an agent skill from irahardianto/awesome-agv. Rust idioms: ownership and borrow checker patterns, error handling with thiserror/anyhow, Tokio async concurrency, lifetime management, and Clippy pedantic compliance. Use when writing, optimizing, or reviewing Rust crates.
Its SKILL.md is about 6.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 6 other files, including reference files (for example `references/project-structure.md`, `references/recommended-dependencies.md` and `references/rust-patterns-and-anti-patterns.md`).
It sits in Development. It works with Rust. The repository describes itself as: Comprehensive sets of standards and practices designed to elevate the capabilities of AI coding agents. The licence is MIT.
4 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 9e997ba. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
cargoFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Rust Idioms loads about 6.8k tokens when it runs, and up to ~23k if it reads all its reference files. Until then it costs about 59 tokens; SKILL.md has 2,324 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from irahardianto/awesome-agv at commit 9e997ba, republished under its MIT licence (© irahardianto). 2,324 words, ~6,840 tokens.
.claude/skills/rust-idioms/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.Rust's type system and ownership model are your primary tools for correctness. Lean into the compiler — it is your strongest ally. Write code that is idiomatic, safe, and expressive.
Scope: This file covers Rust-specific coding idioms. For file layout, see
references/project-structure.md(in this skill). For detailed safety, SAST security invariants, and performance anti-patterns, seereferences/rust-patterns-and-anti-patterns.md(in this skill). For Rust test naming and conventions, see §Testing below; for universal testing principles, see@.agents/rules/testing-strategy.md. For logging library choice and setup, see@.agents/skills/logging-implementation/SKILL.md.
Default to the latest stable Rust. As of July 2026, this is Rust 1.97. All guidance in this skill assumes latest stable features. When creating new projects, set
rust-versioninCargo.tomlto prevent builds on outdated toolchains.
[package]
edition = "2024"
rust-version = "1.97"Key version milestones that affect this skill:
async fn in traits (no async_trait crate needed for static dispatch). This milestone is the single source of truth for the async-trait crate policy:impl MyTrait return params or generic T: MyTrait bounds use native async fn in traits; no crate required and zero dispatch overhead.async-trait crate only when dynamic dispatch via dyn Trait is explicitly required — e.g. Box<dyn MyTrait>, Arc<dyn MyTrait> for runtime polymorphism, object-safe trait objects, or storing heterogeneous trait impls in a collection.async-trait as a default dependency just for ergonomics — it adds a heap allocation and dynamic dispatch cost. Add it only for the specific crates/traits that need dyn dispatch.[workspace.lints])Mutex::new() in const context (no OnceCell wrapper needed)For recommended crate versions and starter
Cargo.toml, seereferences/recommended-dependencies.md.
Prefer borrowing (&T, &mut T) over cloning
.clone() to silence the borrow checker without a // CLONE: comment explaining whyCow<'_, T> when a function may or may not need ownership&str over String in function parameters, &[T] over Vec<T>Minimize owned data in structs
String, Vec<T>) when the struct must outlive its inputsAvoid unnecessary Arc<Mutex<T>>
tokio::sync::mpsc)RwLock over MutexArc<T> without a lockRespect the Copy / Clone boundary:
.clone() on types that implement Copy (e.g., i32, f64, bool, char, usize, Option<CopyType>).clone() is misleading and suggests heap allocationCopy = bitwise copy (stack only); Clone = potentially expensive deep copy// ❌ Misleading — usize implements Copy
let count = other_count.clone();
// ✅ Implicit copy — clear and correct
let count = other_count;Use the ? operator for propagation — never unwrap() in production code
unwrap() and expect() are acceptable only in:#[test], #[tokio::test])// SAFETY: comment)main() function with clear error messages via expect("reason")Choose error crates by context:
| Context | Crate | Reason |
|---|---|---|
| Library crates | thiserror | Typed, matchable errors. Callers need to handle specific variants. |
| Web service HTTP errors | thiserror | AppError enum must implement IntoResponse — typed variants required. |
| Service/domain layer errors | thiserror | Domain errors need structured variants for logging and client responses. |
| Application glue / scripts / CLI | anyhow | Error type doesn't matter; ergonomic propagation is all you need. |
Web service rule: Use
thiserrorforAppError(HTTP handler errors) and domain errors.anyhow::Errordoes NOT implementIntoResponseand cannot be returned from Axum handlers. Useanyhowonly in non-HTTP utility code (scripts, migration runners, CLI entrypoints) where errors are printed, not sent over the wire.The idiomatic pattern is
thiserrorfor typed variants +#[from] anyhow::Erroras the catch-allInternalvariant inAppError. Seeaxum-idioms/SKILL.md§Error Handling for the complete pattern.Never add
anyhowas a dependency to library crates — it leaks a concrete error type into your public API.
Error type design:
// ✅ Good — typed, matchable errors
#[derive(Debug, thiserror::Error)]
pub enum PathfinderError {
#[error("file not found: {path}")]
FileNotFound { path: PathBuf },
#[error("AST parse failed: {0}")]
ParseError(String),
#[error(transparent)]
Io(#[from] std::io::Error),
}
// ❌ Bad — stringly-typed, unmatchable
fn do_thing() -> Result<(), String> { ... }
// ✅ Use #[must_use] on functions returning non-Result types that callers must handle
#[must_use]
pub fn compute_checksum(data: &[u8]) -> u64 { ... }
// ℹ️ Result<T, E> already has #[must_use] in std — adding it to Result-returning
// functions is redundant. The compiler warns on unused Result values automatically.
pub fn create_task(req: CreateTaskRequest) -> Result<Task, TaskError> { ... }Use lazy evaluation for fallback values:
unwrap_or_else(|| expr) instead of unwrap_or(expr) when the fallback involves a function callexpect messages should be string literals, not format!() callsmap_or_else instead of map_or when either branch involves computation// ❌ Eager — default_value() is called even when result is Ok
let val = result.unwrap_or(default_value());
let msg = result.expect(&format!("failed for {id}"));
// ✅ Lazy — default_value() only called when needed
let val = result.unwrap_or_else(|_| default_value());
let msg = result.unwrap_or_else(|e| panic!("failed for {id}: {e}"));Use tokio as the async runtime
#[tokio::main] or #[tokio::test]tokio::spawn for concurrent tasks, not std::thread::spawntokio::select! for racing futures, not manual pollingCancellation safety:
tokio::sync::mpsc over tokio::sync::broadcast unless fan-out is neededasync fn that holds resources across .awaittokio_util::sync::CancellationToken for graceful shutdownBlocking operations:
tokio::task::spawn_blocking for CPU-heavy or blocking worktokio::fs instead of std::fs inside async functionsUse tracing instead of log for all structured diagnostics in async applications:
tracing is span-aware — log entries inherit context from parent spans (correlation IDs, request metadata)log is fire-and-forget with no span concept — unsuitable for async where context flows across .await boundaries#[tracing::instrument] on async functions to automatically create spans with function arguments@.agents/skills/logging-implementation/SKILL.md §Rust for the full setupZero unsafe blocks unless in FFI boundaries
unsafe block must have a // SAFETY: comment explaining the invariantMinimize unsafe surface area:
unsafe in a safe wrapper functionunsafe wrappersNever use unsafe to bypass the borrow checker — restructure the code instead
Prefer '_ lifetime elision when possible
'a for single lifetime parameters, descriptive names ('input, 'query) for multipleKeep generic bounds simple:
impl Trait in argument position for simple caseswhere clauses for complex bounds — never inline complex bounds in <...>Avoid lifetime gymnastics:
ArcBuilder pattern for types with many optional fields:
Self from builder methods for chainingbuild() returns Result<T, BuildError>, not TNewtype pattern for domain types:
struct UserId(u64), not bare u64Deref only when the newtype truly "is-a" the inner typeTypestate pattern for state machines:
From/Into conversions:
From<A> for B (never Into directly)impl From<X> for Error with thiserror's #[from] attributePrefer T::new() over Default::default() for known types:
Vec::new(), String::new(), HashMap::new() — explicit, readable, idiomaticDefault::default() in generic contexts where T: Default bounds are neededDefault::default() in struct update syntax: MyStruct { field: value, ..Default::default() }// ✅ Idiomatic — explicit constructor for known types
let items: Vec<String> = Vec::new();
let name = String::new();
let map: HashMap<String, i32> = HashMap::new();
// ✅ Also good — capacity hint is valuable
let items = Vec::with_capacity(100);
// ✅ Default::default() in generic code — correct usage
fn create_collection<T: Default>() -> T {
T::default()
}
// ✅ Default::default() in struct update syntax
let config = ServerConfig {
port: 8080,
..Default::default()
};Use stdlib convenience methods — avoid manual reimplementations:
str.split_once(pat) instead of manual splitn(2, pat) + indexinga.min(b) / a.max(b) / a.clamp(lo, hi) instead of match a.cmp(&b) { ... }Ordering::then() / Ordering::then_with() for multi-field comparisons// ❌ Manual reimplementation
let parts: Vec<&str> = s.splitn(2, ':').collect();
let key = parts[0];
let value = parts.get(1).unwrap_or(&"");
// ✅ Idiomatic — clearer intent, less code
let (key, value) = s.split_once(':').unwrap_or((s, ""));
// ❌ Redundant match over Ordering
match a.cmp(&b) {
Ordering::Less | Ordering::Equal => a,
Ordering::Greater => b,
}
// ✅ Direct
a.min(b)
// ❌ Redundant let-binding
let result = compute_something();
result
// ✅ Return directly
compute_something()Keep function complexity low (cyclomatic complexity < 10):
match arms into named helper functionsif !condition { return Err(...) }) to flatten nesting// ❌ High complexity — nested match + conditionals
fn process(input: &Input) -> Result<Output> {
match input.kind {
Kind::A => {
if input.flag {
// 20 lines...
} else {
// 20 lines...
}
}
Kind::B => { /* another 30 lines */ }
}
}
// ✅ Decomposed — each function has single responsibility
fn process(input: &Input) -> Result<Output> {
match input.kind {
Kind::A => process_kind_a(input),
Kind::B => process_kind_b(input),
}
}Test organization (Rust-specific — differs from Go/TS):
For the authoritative test layout rules (unit vs integration vs e2e placement,
#[cfg(test)]conventions,tests/common/mod.rspattern,#[tokio::test]usage), seereferences/project-structure.md§Testing Layout. The rules are co-located there to stay in sync with the directory layout they describe.
Test naming: fn test_<function>_<scenario>_<expected>() (snake_case)
Assertions:
assert_eq! / assert_ne! over assert!(a == b) — better error messagesassert!(matches!(result, Ok(_))) for enum variant checkingassert!(true) or assert!(false):assert!(false) / debug_assert!(false) → use unreachable!("reason") or panic!("reason")assert!(true) → remove entirely (it tests nothing)Property testing: Use proptest (preferred) or quickcheck for functions with wide input spaces. proptest is preferred for its superior strategy composability, automatic shrinking, and more expressive generators.
Test coverage is non-negotiable for new code:
pub fn, pub struct method, and impl block MUST have at least one testif/else, match arm, error path) MUST be exercised by a testcargo tarpaulin or cargo llvm-cov to verify coverage locally before committing# Quick coverage check during development
cargo tarpaulin --workspace --skip-clean --out stdout
# Generate detailed report
cargo llvm-cov --workspace --lcov --output-path lcov.infoTest double selection — choose the right tool:
| Approach | When to Use | Crate |
|---|---|---|
| Hand-written fake | Simple trait, few methods, test needs custom stateful behavior | None (implement trait directly) |
mockall | Complex trait, need to verify call counts, argument matching, or call ordering | mockall |
| Parameterized tests | Same logic, multiple input/output pairs (like Go table-driven tests) | rstest |
| Snapshot testing | Large outputs (JSON responses, CLI output, error messages) | insta |
// ✅ Hand-written fake — simple, debuggable, no macro magic
struct FakeTaskStorage {
tasks: HashMap<String, Task>,
}
impl TaskStorage for FakeTaskStorage {
async fn get_by_id(&self, id: &str) -> Result<Task, StorageError> {
self.tasks.get(id).cloned().ok_or(StorageError::NotFound)
}
}
// ✅ mockall — when you need interaction verification
#[cfg(test)]
mock! {
pub TaskStore {}
impl TaskStorage for TaskStore {
async fn get_by_id(&self, id: &str) -> Result<Task, StorageError>;
async fn create(&self, task: &Task) -> Result<(), StorageError>;
}
}
#[tokio::test]
async fn test_service_calls_storage_once() {
let mut mock = MockTaskStore::new();
mock.expect_create()
.times(1)
.returning(|_| Ok(()));
let service = TaskService::new(mock);
service.create_task(request).await.unwrap();
}
// ✅ rstest — parameterized test cases
use rstest::rstest;
#[rstest]
#[case("valid@email.com", true)]
#[case("no-at-sign", false)]
#[case("", false)]
fn test_email_validation(#[case] input: &str, #[case] expected: bool) {
assert_eq!(is_valid_email(input), expected);
}
// ✅ insta — snapshot testing for complex outputs
use insta::assert_json_snapshot;
#[test]
fn test_task_response_shape() {
let response = TaskResponse::from(sample_task());
assert_json_snapshot!(response);
}Prefer hand-written fakes for core domain traits — they are easier to debug and don't couple tests to implementation details. Use
mockallonly when the trait has many methods or you genuinely need interaction verification (call counts, argument matching, call ordering). Over-mocking withmockallleads to brittle tests that break on implementation changes.
cargo check for fast iteration during development
cargo check: type-checks without producing a binary — fastest feedback loopcargo clippy: includes cargo check plus lint rules — use before committingcargo build: only when you need the actual binary/library artifactcargo build during TDD cycles — it is significantly slower than cargo checkcargo clippy must pass with zero warnings before any commit
Clippy suppression policy — fix the code, don't silence the lint:
NEVER suppress these lints — they signal structural problems that must be fixed:
| Lint | What It Signals | What To Do Instead |
|---|---|---|
too_many_lines | Function is monolithic | Decompose into smaller functions (see Idiomatic Patterns §7) |
cognitive_complexity | Too many branches/nesting | Flatten with early returns, extract match arms |
too_many_arguments | Function has too many params | Introduce a params/config struct or builder |
type_complexity | Nested generics are unreadable | Create a type alias or newtype wrapper |
struct_excessive_bools | Struct has too many boolean fields | Replace with an enum, bitflags, or config sub-struct |
large_enum_variant | Enum variant is disproportionately large | Box the large variant's payload |
Decomposition strategies (use INSTEAD of #[allow]):
// ❌ FORBIDDEN — agent took the lazy path
#[allow(clippy::too_many_lines)]
fn process_request(req: &Request) -> Result<Response> {
// 200 lines of code...
}
// ✅ REQUIRED — decompose the function
fn process_request(req: &Request) -> Result<Response> {
let validated = validate_request(req)?;
let enriched = enrich_with_context(&validated)?;
build_response(&enriched)
}
// ❌ FORBIDDEN — too many arguments
#[allow(clippy::too_many_arguments)]
fn create_server(host: &str, port: u16, tls: bool, timeout: u64,
max_conn: usize, log_level: &str, cert: &Path) -> Server { ... }
// ✅ REQUIRED — params struct
struct ServerConfig {
host: String,
port: u16,
tls: bool,
timeout: Duration,
max_connections: usize,
log_level: Level,
cert_path: PathBuf,
}
fn create_server(config: ServerConfig) -> Server { ... }
// ❌ FORBIDDEN — hiding type complexity
#[allow(clippy::type_complexity)]
fn get_handlers() -> HashMap<String, Box<dyn Fn(&Request) -> Pin<Box<dyn Future<Output = Response>>>>> { ... }
// ✅ REQUIRED — type alias
type HandlerFn = Box<dyn Fn(&Request) -> Pin<Box<dyn Future<Output = Response>>>>;
fn get_handlers() -> HashMap<String, HandlerFn> { ... }Acceptable suppressions (with mandatory // ALLOW: comment):
| Lint | When Acceptable |
|---|---|
unwrap_used | In #[cfg(test)] modules only |
expect_used | In #[cfg(test)] modules, OR with a // SAFETY: comment proving infallibility, OR in a CLI main() that owns the process exit (clear message + exit code). This reconciles with the expect_used = "warn" lint level in recommended-dependencies.md — warn permits these uses while still surfacing every other expect() for review. |
module_name_repetitions | When the repetition is intentional API design |
must_use_candidate | On internal functions where the caller pattern is known |
missing_errors_doc | Temporarily during development (must be resolved before merge) |
needless_pass_by_value | When API stability requires it (with comment explaining why) |
items_after_statements | When locality of helper functions improves readability |
cast_possible_truncation | With bounds check or range validation immediately preceding the cast |
Rule of thumb: If you're about to write #[allow(clippy::...)], stop and ask: "Am I suppressing a real design problem?" If yes, fix the design. If the lint is genuinely a false positive for this specific context, suppress with a // ALLOW: comment explaining the rationale.
cargo fmt is non-negotiable — all code must be formatted
Recommended project-level Clippy configuration:
For the standard
[lints.clippy]and[lints.rust]blocks (single-crate and workspace variants), and the version pinning policy, seereferences/recommended-dependencies.md§Workspace Lint Configuration and §Starter Cargo.toml Template. Do not duplicate those blocks here — treatrecommended-dependencies.mdas the single source of truth.
Document all public items:
pub fn, pub struct, pub enum, pub trait, and pub type MUST have a /// doc commentmissing_docs lint in library crates:# In Cargo.toml
[lints.rust]
missing_docs = "warn"// ❌ Undocumented public item
pub fn resolve_symbols(path: &Path) -> Result<Vec<Symbol>> { ... }
// ✅ Documented
/// Resolves all exported symbols from the file at `path`.
///
/// Returns parsed symbol definitions including their span information.
///
/// # Errors
/// Returns `ParseError` if the file cannot be parsed by tree-sitter.
pub fn resolve_symbols(path: &Path) -> Result<Vec<Symbol>> { ... }Cargo.toml — use dep = "1" not dep = "*"cargo audit to check for known vulnerabilitiesFeatures must be additive — enabling a feature must only add functionality, never change or remove existing behavior
Use dep: syntax for optional dependencies to keep the feature namespace clean:
[features]
default = ["json"]
json = ["dep:serde_json"] # ✅ Uses dep: prefix
grpc = ["dep:tonic"] # ✅ Feature doesn't auto-expose dep as featureGuard feature-gated code with #[cfg(feature = "...")]:
#[cfg(feature = "grpc")]
pub mod grpc_handler;Test feature combinations in CI using cargo-hack:
cargo hack test --feature-powerset --depth 2Never use features for mutually exclusive backends — use traits and runtime selection instead
Never use string literals directly in std::env::var():
// ❌ Bug-prone — typos are silent, scattered across codebase
let port = std::env::var("PATHFINDER_PORT").unwrap_or("3000".into());
let host = std::env::var("PATHFNDER_HOST").unwrap_or("localhost".into()); // typo!
// ✅ Safe — constants catch typos at compile time, single source of truth
mod env_keys {
pub const PORT: &str = "PATHFINDER_PORT";
pub const HOST: &str = "PATHFINDER_HOST";
}
let port = std::env::var(env_keys::PORT).unwrap_or_else(|_| "3000".into());
let host = std::env::var(env_keys::HOST).unwrap_or_else(|_| "localhost".into());Prefer structured config parsing over scattered env::var calls:
Key safety rules (non-negotiable):
unsafe without a // SAFETY: comment documenting the invarianttransmute across types of different sizes or with different validity invariantsas casts with explicit bounds checks — as silently truncatestokio::task::spawn_blocking for CPU-heavy or synchronous I/O work inside async contextsFor the full catalog of safety invariants, SAST patterns, concurrency rules (lock guards, atomics, async), memory safety (double indirection, transmute, pointer casts), collection best practices (retain, deterministic iteration), and security (TOCTOU, path traversal, cookie flags, CSP), see
references/rust-patterns-and-anti-patterns.md. Load it before writing any unsafe code, concurrent code, or I/O handling code.For performance patterns (arena allocation, SmallVec, zero-copy parsing, Cow, pre-sized collections, benchmarking), see
perf-optimization/languages/rust.md.
© irahardianto, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 5 other files (references) in .agents/skills/rust-idioms of irahardianto/awesome-agv.
Open the folder on GitHubat commit 9e997ba
Rust Idioms next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Rust Idioms this skillirahardianto/awesome-agv | 156 | — | ~6.8k | Automated safety check: Pass | MIT | |
| Migrate Core Code to Submodulestinyhumansai/openhuman | 42k | — | ~2.6k | Automated safety check: Pass | GPL-3.0 | |
| OpenLogi macOS Permissions TriageAprilNEA/OpenLogi | 23k | — | ~2.5k | Automated safety check: Notes | Apache-2.0 | |
| Rust Best Practicesfarm-fe/farm | 5.6k | 3 repos | ~1.1k | Automated safety check: Pass | MIT | |
| RTK Rust Design Patternsrtk-ai/rtk | 83k | — | ~1.9k | Automated safety check: Pass | Apache-2.0 | |
| Release Skillsnexmoe/eve | 421 | 3 repos | ~3.3k | Automated safety check: Pass | None |
tinyhumansai/openhuman
Plans and carries out moving non-host-specific code and its tests from the OpenHuman core into vendored tiny submodule libraries, then releases the submodule and re-pins the host.
AprilNEA/OpenLogi
Decides whether an OpenLogi device problem on macOS is a privacy-permission (TCC) problem, using agent log lines, and says which identity needs which grant.
farm-fe/farm
Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook.
rtk-ai/rtk
Describes seven Rust design patterns for the RTK CLI filter modules, with when to use each, RTK examples, and notes on when a pattern is overkill.
nexmoe/eve
Universal release workflow. An agent skill from nexmoe/eve.
teambit/bit
Work on the pnpm Rust engine (@pnpm/napi, the pacquet crates) that bit install runs through.
irahardianto/awesome-agv
Commits to one bold aesthetic direction, sets up a CSS token system for it, then builds the interface in Vue or plain HTML using those tokens.
irahardianto/awesome-agv
Profile-driven performance optimization protocol. An agent skill from irahardianto/awesome-agv.
irahardianto/awesome-agv
Coding conventions for Angular 19 and later: standalone components, signals, OnPush change detection, lazy routes and where RxJS still belongs.
irahardianto/awesome-agv
Rules for designing CI/CD pipelines in layers: universal lint, test and scan stages, container builds with SBOM attestation, and GitOps for orchestrated deployments.
irahardianto/awesome-agv
Hono lightweight web framework patterns: type-safe route handlers, middleware composition, Zod validation, and RPC clients for Cloudflare Workers, Node, or Bun.
irahardianto/awesome-agv
Mobile E2E testing patterns — Flutter integrationtest, Patrol, Maestro, golden testing, device matrix, and test data management.
Works with
Categories
Rust idioms: ownership and borrow checker patterns, error handling with thiserror/anyhow, Tokio async concurrency, lifetime management, and Clippy pedantic compliance. Rust Idioms is an agent skill from irahardianto/awesome-agv. Rust idioms: ownership and borrow checker patterns, error handling with thiserror/anyhow, Tokio async concurrency, lifetime management, and Clippy pedantic compliance.
Rust Idioms fits situations like: reviewing Rust crates.
Run `npx skills add irahardianto/awesome-agv --skill rust-idioms -a claude-code`. Or copy the skill folder (.agents/skills/rust-idioms in irahardianto/awesome-agv) into .claude/skills/rust-idioms in your project. Claude Code loads it when a task matches its description.
Run `npx skills add irahardianto/awesome-agv --skill rust-idioms -a codex`. Or copy the skill folder (.agents/skills/rust-idioms in irahardianto/awesome-agv) into .agents/skills/rust-idioms in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add irahardianto/awesome-agv --skill rust-idioms -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/rust-idioms, .gemini/skills/rust-idioms, .github/skills/rust-idioms and .opencode/skills/rust-idioms in your project.
Going by SKILL.md and its folder, Rust Idioms needs the command-line tools its instructions call (cargo).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Rust Idioms is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.8k tokens (SKILL.md is roughly 27k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 16k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Rust Idioms: Migrate Core Code to Submodules (tinyhumansai/openhuman, 42k stars), OpenLogi macOS Permissions Triage (AprilNEA/OpenLogi, 23k stars), Rust Best Practices (farm-fe/farm, 5.6k stars) and RTK Rust Design Patterns (rtk-ai/rtk, 83k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
irahardianto (a GitHub user) maintains it in irahardianto/awesome-agv, which has 156 GitHub stars. The repository holds 34 skills in this directory. The repository was last updated on October 5, 2026.
Source: irahardianto/awesome-agv on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.