From research-engineering-skills
Set up a Python project so files are simultaneously marimo interactive notebooks and pytest test modules — assertions are the source of truth, cells render the results. Use when the user wants notebooks that double as tests, asks to wire up marimo with pytest, or wants executable documentation/tutorials that stay green in CI.
How this skill is triggered — by the user, by Claude, or both
Slash command
/research-engineering-skills:marimo-notebook-testsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Set up a Python project so that `notebooks/*.py` are simultaneously
Set up a Python project so that notebooks/*.py are simultaneously
marimo interactive notebooks and pytest test modules.
Assumes marimo is installed as a dev dependency alongside pytest.
Every notebook file has three layers:
import marimo
app = marimo.App(width="medium")
# 1. test_* functions at module level — importable, pytest-visible.
# Convention: return results so cells can reuse them for display
# without running the logic twice.
def test_something():
from mylib import thing
result = thing()
assert result == expected
return result
# 2. @app.cell functions — marimo reactive UI.
# mo is imported once in the first cell and flows as a dependency.
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _(mo):
result = test_something() # assertion always runs inside the cell
return (mo.md(f"✓ result: {result}"),)
# 3. entry point — launches the notebook UI when run directly
if __name__ == "__main__":
app.run()
| command | behaviour |
|---|---|
pytest notebooks/ | finds test_* functions at module level, runs assertions |
marimo run notebooks/foo.py | interactive notebook; cells call test_* then render prose |
python notebooks/foo.py | launches the notebook UI |
from notebooks.foo import test_x | plain import, marimo never invoked |
[project.optional-dependencies]
test = ["pytest>=7", "marimo>=0.9", "discopy>=1.0"] # marimo is a dev dep
[tool.pytest.ini_options]
testpaths = ["tests"] # default: fast unit tests only
# to include notebook integration tests: pytest tests/ notebooks/
test_* functions never import marimo — pure logic, no UI coupling.import marimo as mo lives in the first cell only; all subsequent
cells receive mo as a parameter via marimo's dependency injection.@app.cell returns a Cell object, not the original function, so
pytest will not accidentally treat cell functions as tests._ are fine: marimo registers each before the
name is rebound; pytest ignores underscore-prefixed names.test_* first, then display — the assertion is the
single source of truth, the cell just renders the result.tests/tutorials/ — preferred for a maths/PL library. Sits inside the
existing test tree alongside unit tests, directly mirroring the
test/tutorials/ convention in JuliaSymbolics/Metatheory.jl. Since pytest
recurses into tests/, no extra testpaths config is needed.notebooks/ — alternative if docs-primary identity is preferred.npx claudepluginhub 0x0f0f0f/research-engineering-skills --plugin research-engineering-skillsProvides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.