Python notebooks async
Agent skills
npx -y skills add ahgraber/skills --skill python-notebooks-asyncAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 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
Use when writing or reviewing asyncio code in Jupyter notebooks or '#%%' cell workflows — structuring event-loop ownership, orchestrating async tasks, or choosing compatibility strategies. Also use when hitting RuntimeError: This event loop is already running, asyncio.run() failures in cells, or tasks silently never completing.
SKILL.md
3.3 KB, as published. Nobody here has run it
Python Notebooks Async
Overview
Notebook kernels own the event loop; async code must cooperate with that ownership rather than fight it.
This skill covers orchestration patterns, top-level await, and compatibility constraints for .ipynb and #%% workflows.
Treat these recommendations as preferred defaults. When project constraints require deviation, call out tradeoffs and compensating controls.
When to Use
asyncio.run()raisesRuntimeErrorinside a notebook cell.- Event-loop conflicts when mixing async libraries in Jupyter.
- Porting async scripts into notebook workflows.
- Orchestrating concurrent tasks (
gather,TaskGroup) in IPython kernels. - Deciding where to place reusable async logic across notebook/module boundaries.
When NOT to Use
- Pure script or service code with no notebook involvement — see
python-concurrency-performance. - Synchronous notebook workflows with no async needs.
- General asyncio API design outside notebook contexts — see
python-runtime-operations.
Quick Reference
- Treat notebook kernels as loop-owned environments; never create a competing loop.
- Use top-level
awaitinstead ofasyncio.run()in notebook cells. - Orchestrate concurrent work with
asyncio.gather()orasyncio.TaskGroup. - Keep reusable async logic in regular
.pymodules, imported into notebooks. - Use
nest_asyncioonly as a constrained compatibility fallback, not a default. - Avoid fire-and-forget tasks — always
awaitor collect results explicitly.
Common Mistakes
- Calling
asyncio.run()in a notebook cell. The kernel already runs a loop;asyncio.run()tries to start a second one and raisesRuntimeError. Useawaitdirectly instead. - Applying
nest_asyncioglobally by default. It patches the loop to allow reentrant calls but masks design problems and can hide subtle concurrency bugs. Reserve it for legacy compatibility. - Defining async helpers inline in cells instead of modules.
Inline definitions are lost on kernel restart and cannot be tested outside the notebook.
Extract to
.pyfiles. - Ignoring returned tasks or coroutines.
Calling an async function without
awaitsilently produces a never-executed coroutine object, with no error until results are missing downstream. - Mixing blocking I/O with async in the same cell.
Synchronous calls like
requests.get()block the event loop, starving concurrent tasks. Useaiohttp,httpx, orasyncio.to_thread().
Scope Note
- Treat these recommendations as preferred defaults for common cases, not universal rules.
- If a default conflicts with project constraints or worsens the outcome, suggest a better-fit alternative and explain why it is better for this case.
- When deviating, call out tradeoffs and compensating controls (tests, observability, migration, rollback).
Invocation Notice
- Inform the user when this skill is being invoked by name:
python-design-modularity.
References
references/notebooks-async.md