
Rust Review
Review Rust services for async slop—unnecessary async, blocking I/O on the runtime, and spawn-heavy patterns—before you merge or release.
Overview
Rust Review is an agent skill for the Ship phase that detects Rust async slop—async functions without awaits, blocking I/O on async runtimes, and spawn-heavy defaults—in code review.
Install
npx skills add https://github.com/athola/claude-night-market --skill rust-reviewWhat is this skill?
- Flags async fn bodies with no .await and suggests stripping async coloring
- Detects blocking I/O (std::fs, thread::sleep) inside async contexts
- Documents tokio::spawn overuse and structural async anti-patterns
- Preferred detection: cargo clippy -W clippy::async_yields_async
- File-level rg heuristics when clippy is unavailable, with manual follow-up
- Module estimated_tokens: 500 in skill frontmatter
- Primary lint: clippy::async_yields_async via cargo clippy --all-targets
Adoption & trust: 2 installs on skills.sh; 304 GitHub stars; 3/3 security scanners passed (skills.sh audits); trending (+200% hot-view momentum).
What problem does it solve?
AI-assisted Rust often adds async and tokio::spawn everywhere, spreading async-only APIs and blocking the runtime without you noticing in a quick diff.
Who is it for?
Indie developers reviewing Tokio/async Rust crates or services after agent-generated changes.
Skip if: Greenfield projects with no async code, teams that only need generic language-agnostic review, or Rust embedded/no-std codebases.
When should I use this skill?
Reviewing Rust async code, before merge, or when auditing agent-generated Tokio services
What do I get? / Deliverables
You get a focused review checklist and clippy commands that surface fixable async anti-patterns before merge.
- List of async slop patterns matched per file or function
- Suggested signature and I/O fixes (sync vs async, spawn vs inline)
Recommended Skills
Journey fit
Ship is where you gate merges and releases; async mistakes are correctness and perf bugs you want caught in review, not in production. Review subphase matches code-review and clippy-driven detection workflows described in the module.
How it compares
Narrow async-structure linter guidance for Rust review, not a full cargo-audit or security scanner.
Common Questions / FAQ
Who is rust-review for?
Solo builders and small teams shipping async Rust who want a structured pass for LLM-typical async mistakes before merge.
When should I use rust-review?
During Ship → review on Rust PRs and pre-release branches, especially after Codex or Claude edits async services or CLI tools.
Is rust-review safe to install?
The skill describes read/grep/clippy workflows; confirm trust via the Security Audits panel on this Prism page before installing from any marketplace.
SKILL.md
READMESKILL.md - Rust Review
# Async Slop **AI defaults to `async` and `tokio::spawn` even where sync code is faster, simpler, and correct.** This module covers the high-frequency async patterns that look idiomatic but are not. The clippy lints catch some; the rest is structural. ## Pattern 1: `async fn` that contains no `.await` ```rust // SLOP async fn compute_total(items: &[Item]) -> u64 { items.iter().map(|i| i.price).sum() } ``` If the function body has no `.await`, it has no reason to be `async`. Async coloring is contagious: this function is callable only from async contexts, forcing every caller to also be `async`. Strip `async` from the signature unless the body actually awaits. Detection (preferred: clippy): ```bash cargo clippy --all-targets -- -W clippy::async_yields_async ``` File-level heuristic when clippy is unavailable: ```bash for f in $(rg -l "async fn " --type rust); do rg -q "\.await" "$f" || echo "no-await: $f" done ``` (Heuristic; manual review needed since `.await` may be in a helper called by the async fn rather than inline.) ## Pattern 2: blocking I/O inside an async runtime ```rust // SLOP async fn read_config() -> Result<String> { Ok(std::fs::read_to_string("config.toml")?) } // SLOP async fn rate_limit_wait() { std::thread::sleep(Duration::from_secs(1)); // blocks the runtime } // SLOP async fn query_db(conn: &Connection) -> Result<Vec<Row>> { conn.query("SELECT ...")? // blocking driver } ``` Blocking calls inside `async` block the entire executor thread, defeating the runtime's concurrency model. Fix: ```rust // Use the async equivalent async fn read_config() -> Result<String> { Ok(tokio::fs::read_to_string("config.toml").await?) } // Or wrap blocking work in spawn_blocking async fn rate_limit_wait() { tokio::time::sleep(Duration::from_secs(1)).await; } // For unavoidable blocking work async fn query_db(conn: Arc<Connection>) -> Result<Vec<Row>> { let conn = conn.clone(); tokio::task::spawn_blocking(move || conn.query("SELECT ...")) .await? } ``` Detection: ```bash # Find blocking ops inside async functions (heuristic) rg -B 5 "(std::fs::|std::thread::sleep|std::net::TcpStream)" --type rust | rg -B 5 "async fn" ``` ## Pattern 3: `tokio::spawn` for synchronous-equivalent work ```rust // SLOP async fn handle_request(req: Request) -> Response { let result = tokio::spawn(async move { compute_response(&req) }).await.unwrap(); result } ``` Spawning a task only to immediately await its single completion is equivalent to a direct call, plus the overhead of task creation, scheduling, and a join. Just call the function: ```rust async fn handle_request(req: Request) -> Response { compute_response(&req) } ``` `tokio::spawn` is for *concurrent* work: when the spawned task should make progress while the caller does something else, or when the task should outlive the caller. A spawn-then-immediately-await is a smell. ## Pattern 4: `async-trait` on synchronous-equivalent traits ```rust // SLOP #[async_trait] trait Greeter { async fn greet(&self, name: &str) -> String; } ``` If the implementation has no `.await` and just returns a synchronous value, `async-trait` adds heap allocation (`Box<dyn Future>`) for nothing. Make the trait sync: ```rust trait Greeter { fn greet(&self, name: &str) -> String; } ``` Use `async-trait` only when at least one implementation genuinely awaits. ## Pattern 5: explicit `Pin<Box<dyn Future>>` returns ```rust // SLOP fn fetch_data(url: &str) -> Pin<Box<dyn Future<Output = Result<Data>> + Send>> { Box::pin(async move { // body }) } ``` Modern Rust supports `impl Future` in return position: ```rust // Idiomatic fn fetch_data(url: &str) -> impl Future<Output = Result<Data>> + Send { async move { // body } } ``` `Pin<Box<dyn Future>>` is needed only for trait method returns or w