Use when authoring or reviewing a hands-on demo, tour, or walkthrough notebook (`#%%` percent-format or Jupyter) that demonstrates a feature, library, or API and doubles as semi-interactive documentation. Triggers: "write a demo notebook", "build a feature demo", "demo this library/API", "a notebook to walk through X", "interactive docs for this feature". Not for production/analysis notebooks or pure asyncio event-loop mechanics (see python-notebooks-async).
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
A demo notebook does two jobs at once, and must do both:
The orientation is what to teach; the interaction is how to teach it. A notebook that interacts beautifully but explains nothing is a toy; one that explains but only runs as opaque blocks is a slideshow. Clear both bars.
Two failure modes make a notebook performative (a script that happens to have cell markers) rather than interactive:
async def demo_function(...) and calling them as opaque blocks.
The reader can only run the whole block; they cannot step into a single call and tweak it.f"created {name}" instead of showing the evidence — the object the call returned, the before/after, the read-back.
The reader has to take the markdown's word for it.This skill is the bar a demo notebook must clear.
It is language-agnostic in principle; examples use Python because most demo APIs are.
For asyncio event-loop ownership (top-level await, kernel-owns-the-loop), defer to python-notebooks-async.
#%% / percent-format or .ipynb notebook that demonstrates a library, API, or service so a maintainer can experiment with what was built..py and test it.RuntimeError: event loop already running, asyncio.run() in a cell) — see python-notebooks-async.interactive-notebook-demo.
Skip the notice when the user asked for the skill by name or slash command; spelling and spacing need not match.
A phrase from this skill's own trigger list is not a name — naming the work is not naming the skill.A reader should come away understanding the feature, not just a list of callable methods. Convey each of these through the prose and the evidence — never by labeling a cell with the lens name (see Write it, don't announce it, below):
Pull these through as well — they are usually the difference between a tour and real orientation:
main(), no multi-call wrapper functions (one exception below).# not idempotent: re-running adds a revision).
Marking is an expectation, not a judgment call: an unmarked cell is then a trustworthy promise that re-running it is safe.
The reset for accumulated drift is the whole-notebook contract — Restart→Run-All must pass.
Keep the reader's knob in plain view, not buried in setup().# %% [markdown] cell of 2–4 sentences explaining what it demonstrates and why it matters — teach, don't label.
This prose carries the orientation: tie the operation to the motivating problem, surface the mechanism or invariant it shows, define any new term.**Why this exists:**, **What you'll learn:**, or **Story:** prefixes — the first sentence already carries the point.
Give each section a heading that states its claim ("## Edits version — they don't overwrite"), not a bare noun ("## Editing"), so the headings read as the story and the notebook is navigable.
See antislop-writing.print(result.model_dump_json(indent=2)) for a pydantic model), not one cherry-picked field — but skip dumps so large they bury the point.True/False.assert it with the values in the message (assert rb == expected, (rb, expected)): the claim is visible and a wrong value fails the kernel run instead of quietly printing False.await in cells (the kernel owns the loop).
No if __name__ == "__main__" script guard — straight-line python file.py is not a supported mode.
Make cleanup its own clearly-marked final cell the reader runs when done.client.update(record_id=rid, data=payload, expected_revision=3) — explicit names aid comprehension and survive signature drift.
Verify against the real signatures; naive guesses drift (a parameter you'd call path is really path_prefix, version is really target_version).
Read the source before you write the call.try/except Exception around calls that just work — let the reader see the real call and its real result.await, that the reader can edit any input and re-run to explore (git holds the original), the re-run convention (unmarked cells are safe to re-run; # not idempotent cells mutate each run, and Restart→Run-All resets), and any optional dependency the later cells need.async def setup(...), invoked in its own cell that unpacks into notebook-scope variables.
Everything after setup is flattened to one cell per claim.**Where this lives:** label.For a notebook that needs a database, object store, or other services:
docker-compose.yaml on non-conflicting host ports so the demo and test stacks run side by side; document the ports/DSNs in the file header.README.md (how to open in VS Code/Jupyter, how to start the stack, a port table) and a .gitignore for demo artifacts (local DB files, data/temp dirs).The committed .py percent-file is the artifact.
Its top-level awaits are the part most likely to break interactively — so they are exactly what you must execute.
async def main(): ...; asyncio.run(main()) for a quick python run is a trap: it exercises a different program and leaves the real top-level-await artifact unverified. (This is the mistake to catch in review.)#%% file through a live kernel via jupytext + ipykernel, then assert zero unexecuted cells and zero error outputs.
Never commit the generated .ipynb.JUPYTER_* redirects, and the ruff per-file-ignores notebooks need (F704 top-level await, E402, B018, D, S) are in references/headless-validation.md.await demo_topic(...) block instead of cell-per-claim.print("done"), or a bare True/False, rather than the returned object, the before/after, the read-back.**Why this exists:** / **Story:** prefixes, or bare-noun headings that don't state a point.python file.py path; neither runs the real artifact through a kernel..ipynb — the #%% .py is the source of truth; the executed notebook is a byproduct.references/headless-validation.md — run the real #%% file through a live kernel, sandbox env setup, ruff per-file-ignores, gitignore/README checklist.references/cell-patterns.md — copy-paste cell skeletons: header, section opener, point-into-the-code closer, markdown-then-operation pairing, prove-with-data idioms, the error-demo cell, the connectivity probe, and cleanup.references/notebooks-async.md — event-loop ownership, top-level await, and background-task patterns for demos with async cells (shared from python-notebooks-async).ahgraber/skills
1456a06
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.