Py async patterns
Portable Python code-review skills for agentskills.io-compatible agents — router plus focused skills for type safety, error handling, anti-patterns, async, and code style
npx -y skills add CodeSigils/py-review-skill --skill py-async-patternsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- 29 days oldThe repository was created 29 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Review Python async code for event-loop blocking, missing await, incorrect task/gather usage, swallowed cancellation, missing timeouts, and sync/async boundary mistakes. Use when reviewing asyncio, FastAPI, aiohttp, httpx async clients, background tasks, or concurrent I/O.
SKILL.md
5.2 KB, as published. Nobody here has run it
Python Async Review
Use these rules only for async or concurrent I/O code. Prefer concrete event-loop or cancellation risks over general async style suggestions.
Review Rules
Rule: async-blocking-call
Impact: CRITICAL
Applies when: Code inside async def performs sleeping, HTTP, database, filesystem, subprocess, or CPU-heavy work.
Skip when: The operation is explicitly offloaded to a thread/process or is known non-blocking.
Python: any
Tools: ruff | project-configured
Review signal: time.sleep, requests, sync database clients, or CPU loops appear inside async def.
Incorrect:
async def fetch_data(url: str) -> dict:
time.sleep(1)
return requests.get(url).json()
Correct:
async def fetch_data(url: str) -> dict:
await asyncio.sleep(1)
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()
Reason: Blocking calls stop the event loop and degrade every concurrent request or task.
Rule: async-missing-await
Impact: HIGH
Applies when: Changed code calls an async function.
Skip when: The coroutine is intentionally scheduled with asyncio.create_task and its lifecycle is handled.
Python: any
Tools: pyright | mypy | ruff | project-configured
Review signal: A coroutine-returning function is called without await, create_task, gather, or equivalent scheduling.
Incorrect:
async def handler() -> dict:
result = fetch_user()
return {"user": result}
Correct:
async def handler() -> dict:
result = await fetch_user()
return {"user": result}
Reason: Calling an async function without awaiting or scheduling it returns a coroutine object and does not run the operation.
Rule: async-gather-failure-semantics
Impact: MEDIUM-HIGH
Applies when: Code runs independent async operations concurrently.
Skip when: Failing fast on the first exception is required and documented.
Python: any
Tools: none
Review signal: asyncio.gather is used for independent batch work without deliberate exception handling.
Incorrect:
async def fetch_all(ids: list[str]) -> list[User]:
return await asyncio.gather(*(fetch_user(user_id) for user_id in ids))
Correct:
async def fetch_all(ids: list[str]) -> list[User | Exception]:
return await asyncio.gather(
*(fetch_user(user_id) for user_id in ids),
return_exceptions=True,
)
Reason: Concurrent batch code needs explicit failure semantics: fail fast, collect partial failures, or cancel siblings deliberately.
Rule: async-cancellation-propagates
Impact: CRITICAL
Applies when: Code catches broad exceptions inside async tasks or request handlers.
Skip when: The code catches asyncio.CancelledError only to clean up and then re-raises.
Python: any
Tools: none
Review signal: Broad except Exception/except BaseException around awaited work may swallow cancellation or hide task shutdown.
Incorrect:
async def worker() -> None:
try:
await run_forever()
except BaseException:
logger.exception("worker failed")
Correct:
async def worker() -> None:
try:
await run_forever()
except asyncio.CancelledError:
await cleanup()
raise
except Exception:
logger.exception("worker failed")
raise
Reason: Cancellation is control flow for async shutdown. Swallowing it can hang deployments and leak resources. References: https://docs.python.org/3/library/asyncio-task.html Checked: 2026-07-07 Expires: 2026-10-01
Rule: async-timeout-boundary
Impact: HIGH Applies when: Code awaits network, database, queue, subprocess, or external service calls. Skip when: The called client has a documented timeout configured at construction or service level. Python: any Tools: none Review signal: Awaited external calls have no timeout or cancellation boundary.
Incorrect:
async def load_profile(user_id: str) -> Profile:
return await profile_client.fetch(user_id)
Correct:
async def load_profile(user_id: str) -> Profile:
return await asyncio.wait_for(profile_client.fetch(user_id), timeout=2.0)
Reason: Unbounded awaits can pin request handlers and background workers indefinitely.
Sensitive Evidence Safety
If changed code or tool output reveals a suspected credential, token, private key, secret-bearing URL, or other sensitive value, do not quote or reproduce the value. Report only its existence and location. Treat filename and pattern checks as heuristic evidence, not proof that a repository is secret-free.
If the exposure appears credible, make it the first finding, stop lower-priority review, and recommend revocation or rotation. Never place sensitive values in reports, generated examples, or commit subjects or bodies.