Design and review Rust async code around task ownership, suspension points, cancellation, blocking work, and runtime boundaries.
SkillScore100Maintained
Automatic
◆Coding pack
Last verified 8/16/2026
What it changes
Passed 22 of 22 test cases with the skill, and 21 of 22 without it.
Without skill95%
With skill100%
Checks it passed that the model alone missed
Advises keeping JoinHandles to monitor, await, or abort critical background tasks
1 fixed21 passed either way0 still failing0 broke
Pass-rate lift
+5 pp
Tokens
+11%
Agent turns
0%
Response time
-22%
Model gemini-3.6-flashMeasured 8/16/2026v122 of 22 cases passed with skill
Tokens, turns and time describe resource use, not a dollar price.
See it in action
A test case the skill fixed. Same model, same prompt, with and without the skill.
Prompt
When spawning critical background processing tasks with `tokio::spawn`, is it fine to drop the returned handle immediately if I don't need its immediate return value?
What was checked, without and with the skill
Checked
Without skill
With skill
Advises keeping JoinHandles to monitor, await, or abort critical background tasks
Missed
Passed
case-05 · gemini-3.6-flash · 8/16/2026 · answers are capped and redacted
What's inside
The instructions your model reads when the skill loads.
SKILL.md60 lines2 files
Rust Async Task Design
Use this skill to make Rust async code explicit about task ownership, suspension
points, blocking work, and cancellation. Async is a concurrency model, not a
default replacement for threads or a performance guarantee.
Core Workflow
Identify the async boundary: runtime entrypoint, handler, client call,
stream, background task, or trait method.
Mark every .await as a possible suspension point. Check what state is held
across it.
Use tokio::spawn(async move { ... }) only when the task can own everything
it needs and its future is Send + 'static on the selected runtime.
Keep JoinHandles when task success, panic, cancellation, or shutdown
matters. Do not silently detach important work.
Keep blocking IO and CPU-heavy work out of async tasks. Use async APIs,
spawn_blocking, Rayon, or dedicated threads as the workload requires.
Do not hold a synchronous MutexGuard, RefCell borrow, or non-Send value
across .await.
Add tests for timeout, cancellation, dropped channel, and failed task paths
when those outcomes affect behavior.
Runtime Rules
Read references/async-runtime-patterns.md when reviewing task spawning,
shared state in async code, or blocking work.
Use std::sync::Mutex in async code only for short, low-contention critical
sections that do not cross .await.
Use tokio::sync::Mutex when a lock must be held across .await, but first
consider moving the state behind a task and interacting by messages.
Use spawn_blocking for blocking operations that eventually finish. Limit
parallelism for CPU-heavy work; Tokio's blocking pool can grow large.
Use tokio::time::timeout or explicit cancellation tokens for bounded
operations.
Use select! carefully: dropping a future can cancel it. Check cancellation
safety before using it around IO or partially completed work.