skills/jupyter-to-marimo/SKILL.md
Converts a Jupyter notebook (.ipynb) to a marimo notebook (.py) by running marimo convert, then reviewing and fixing the output for magic commands, IPython display calls, anti-patterns, setup cell completeness, and missing PEP 723 metadata. Use when the user asks to "convert a Jupyter notebook to marimo", "migrate an ipynb to marimo", "turn this notebook into a marimo file", or "convert ipynb to py marimo". Do NOT use for creating new marimo notebooks from scratch (use marimo-notebook), for explaining marimo concepts, or for converting formats other than .ipynb to marimo .py.
npx skillsauth add armandli/get-skilled jupyter-to-marimoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
$ARGUMENTS ends in .ipynb; if not, stop and ask the user for the correct filename..ipynb with .py (same directory).uvx marimo convert <input.ipynb> -o <output.py>
If the command fails, stop and report the error. Do not proceed with a partial or missing output file.
Read the full output file before making any edits. Scan for:
% or %%display(...), HTML(...), Markdown(...), Image(...)with app.setup: blocktry/except used for control flow (bare except Exception returning None)if blocksif dependency: wrapping the entire cell body# /// script block at the top of the file@app.cell function namesApply fixes in this order. Read the full file before each category of edits.
| Magic | Action |
|-------|--------|
| %matplotlib inline | Delete (marimo renders matplotlib automatically) |
| %matplotlib notebook | Delete |
| %load_ext | Delete or # REVIEW: comment |
| %%time, %timeit | Delete the magic line, keep the cell body |
| %pip install pkg | Move pkg to PEP 723 dependencies; delete the magic line |
| %conda install pkg | Move pkg to PEP 723 dependencies; delete the magic line |
| %%bash, %%sh | Replace with subprocess.run(...) or # REVIEW: comment |
| Other % / %% | Replace line with # REVIEW: magic command: <original line> |
display(obj) as the only statement → make obj the final (unindented) expressiondisplay(HTML(s)) → mo.Html(s)display(Markdown(s)) → mo.md(s)display(Image(path)) → mo.image(path)display(...) calls in one cell → mo.vstack([item1, item2, ...])from IPython.display import ... and import IPython lines after replacing all usesMove all top-level import and from ... import statements into the with app.setup: block.
Keep imports in their own cell only if: the import has a meaningful side effect that must run at that point (e.g., setting a backend before other code runs).
If no with app.setup: block exists, create one immediately after app = marimo.App(...):
with app.setup:
import marimo as mo
import typer
# ... other imports
Always include import marimo as mo in the setup cell. Add import typer if the notebook has CLI-style argument cells.
try/except control flow — remove when the except clause just silences errors:
# BEFORE
try:
result = compute()
except Exception:
result = None
# AFTER
result = compute()
Keep try/except only when catching a specific named exception with real recovery logic.
Indented final expression — fix when the only output is inside an if block:
# BEFORE
if condition:
mo.md("text") # won't render
# AFTER
mo.md("text") if condition else None
Overly guarded cells — remove if dependency: wrapping the entire cell body:
# BEFORE
if model:
predictions = model.predict(X)
predictions
# AFTER
predictions = model.predict(X)
predictions
Duplicate cell function names — append _2, _3, etc. to later duplicates.
If the file does not already have a # /// script block, add one at the very top (before any other content):
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "marimo",
# "typer",
# "<package>",
# ]
# ///
Populate dependencies by scanning the setup cell imports. Use this import→PyPI name mapping:
| Import name | PyPI package |
|-------------|--------------|
| numpy | numpy |
| pandas | pandas |
| polars | polars |
| torch | torch |
| sklearn | scikit-learn |
| cv2 | opencv-python |
| PIL | pillow |
| matplotlib | matplotlib |
| altair | altair |
| scipy | scipy |
| seaborn | seaborn |
| plotly | plotly |
| requests | requests |
| typer | typer |
Always include marimo and typer in dependencies.
See references/CONVERSION-PATTERNS.md for full pattern examples.
uvx marimo check <output.py>
If errors are reported, fix and re-run up to 3 cycles. Common errors and fixes:
| Error | Fix |
|-------|-----|
| SyntaxError near % | A magic command was missed; remove it |
| NameError: <name> | Variable defined in IPython global scope; move to setup cell or add as cell arg |
| Cell name collision | Rename duplicate @app.cell function |
| TypeError on display | Replace remaining display(...) call |
If validation still fails after 3 cycles, leave remaining issues as # REVIEW: comments and report them in Step 7.
Provide a structured summary:
## Conversion Summary: <input.ipynb> → <output.py>
**Removed:** <n> magic commands, <n> IPython imports
**Converted:** <n> display() calls, <n> magic commands → PEP 723
**Fixed:** <n> anti-patterns (try/except, indented expr, guards)
**Added:** PEP 723 block with dependencies: [<list>]
**Validation:** PASSED / FAILED (see # REVIEW comments)
**Review Items:** (if any)
- Line <n>: <description of unrecognized pattern>
__generated_with version string.# REVIEW: <original> comments for any pattern you cannot confidently convert.After the skill's primary task completes, run:
python3 ${PWD}/.claude/skills/skill-stat/scripts/record-stat.py "jupyter-to-marimo"
tools
--- name: update-readme description: Updates a project README.md with build instructions, unit test instructions, and a mermaid architecture diagram. Use when a project README needs to be created or refreshed. Trigger phrases: "update readme", "generate readme", "create readme", "refresh readme docs". Emphasizes project interfaces, extension points, and customization hooks in the diagram — not concrete implementations. Do NOT use for documentation sites, wikis, or non-project READMEs. argument-h
business
--- name: skill-stat description: Records skill usage statistics and issue reports into .claude/skill-stats.md. Increments the Uses count for a skill name, and optionally logs an issue report that increments the Issues count and appends a row to the Issue Reports table. Use when tracking how often a skill is invoked, when a user reports a problem with a skill, or when another skill needs to log its own usage. Trigger phrases: "record skill stat", "log skill usage", "report skill issue". Do NOT u
testing
--- name: revert description: Reverts ALL git changes in the working directory: staged changes, unstaged modifications, and new untracked files. Use when user asks to "revert all changes", "undo all changes", "discard all changes", "reset all git changes", or "clean working directory". Do NOT use for reverting a specific file or a specific commit — those need targeted git commands. disable-model-invocation: true --- Revert all git changes in the working directory. This is destructive and cannot
tools
Scans a Python codebase for duplicate or near-duplicate logic patterns across functions, classes, and files, then extracts those patterns into typed utility classes in a shared module. Use when the user asks to "refactor this Python code", "find duplicate logic", "extract shared utilities", "apply DRY to Python", "deduplicate Python code", or "find repeated patterns in Python". Groups extracted helpers by the object type they operate on (strings, numbers, dates, collections, etc.). Do NOT use for performance optimization (use optimize-python), for debugging logic errors, or for explaining code. Do NOT extract code that appears only once. Run this skill before optimize-python.