skills/marimo/SKILL.md
Use when working with marimo notebooks — creating, editing, debugging, converting from Jupyter, or pairing with a running marimo server.
npx skillsauth add edwinhu/workflows 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.
Marimo is a reactive Python notebook where cells form a DAG and auto-execute on dependency changes. Notebooks are stored as pure .py files.
Only edit code INSIDE @app.cell function bodies. This is not negotiable.
NEVER modify:
@app.cell)def _(deps):)ALWAYS verify:
return var,Before claiming ANY marimo notebook works:
marimo check notebook.pymarimo export ipynb notebook.py -o __marimo__/notebook.ipynb --include-outputsThis is not negotiable. Skipping execution and output inspection is NOT HELPFUL — the user gets a notebook that fails when they open it.
marimo check validates syntax and structure only — it never executes cells. Claiming a notebook works because check passed is an unverified claim presented as fact.return var as returning the bare value, which breaks unpacking — single returns require the trailing comma (return var,).@app.cell decorator or def _(...) signature → STOP. Marimo manages these; edit only the function body.marimo check → STOP. Execution with --include-outputs is required.Before every marimo edit:
Structure Validation:
@app.cell function bodiesSyntax Validation:
marimo check notebook.pyRuntime Verification:
marimo export ipynb notebook.py -o __marimo__/notebook.ipynb --include-outputsOnly after ALL checks pass:
Follow this sequence for EVERY marimo task:
1. EDIT → Modify code inside @app.cell function bodies only
2. CHECK → marimo check notebook.py
3. EXECUTE → marimo export ipynb notebook.py -o __marimo__/notebook.ipynb --include-outputs
4. INSPECT → Use notebook-debug verification
5. VERIFY → Outputs match expectations
6. CLAIM → "Notebook works" only after all gates passed
NEVER skip verification gates. Marimo's reactivity means changes propagate unpredictably.
.py files, version control friendly@app.cell decorator patternimport marimo
app = marimo.App()
@app.cell
def _(pl): # Dependencies as parameters
df = pl.read_csv("data.csv")
return df, # Trailing comma required for single return
@app.cell
def _(df, pl):
summary = df.describe()
filtered = df.filter(pl.col("value") > 0)
return summary, filtered # Multiple returns
@app.cell functions only$ in backticks - mo.md("Cost: $50") not mo.md("Cost: $50")| Command | Purpose |
|---------|---------|
| marimo edit notebook.py | marimo: Open notebook in browser editor for interactive development |
| marimo run notebook.py | marimo: Run notebook as executable app |
| marimo check notebook.py | marimo: Validate notebook structure and syntax without execution |
| marimo convert notebook.ipynb | marimo: Convert Jupyter notebook to marimo format |
# marimo: Export to ipynb with code only
marimo export ipynb notebook.py -o __marimo__/notebook.ipynb
# marimo: Export to ipynb with outputs (runs notebook first)
marimo export ipynb notebook.py -o __marimo__/notebook.ipynb --include-outputs
# marimo: Export to HTML (runs notebook by default)
marimo export html notebook.py -o __marimo__/notebook.html
# marimo: Export to HTML with auto-refresh on changes (live preview)
marimo export html notebook.py -o __marimo__/notebook.html --watch
Key difference: HTML export runs the notebook by default. ipynb export does NOT - use --include-outputs to run and capture outputs.
Tip: Use __marimo__/ folder for all exports (ipynb, html). The editor can auto-save there.
For working inside a running marimo notebook kernel — executing code, creating/editing cells, and building notebooks interactively — use the marimo-pair protocol. Full details: marimo-pair/SKILL.md.
See marimo-pair/reference/finding-marimo.md for the full decision tree. Quick start:
# pixi project (our standard)
pixi run marimo edit notebook.py --no-token --watch
# uv project
uv run marimo edit notebook.py --no-token --watch
# standalone / sandbox
uvx marimo@latest edit notebook.py --no-token --watch --sandbox
Always use --watch so the server detects file edits and reloads automatically. Without it, file changes are invisible to the browser and the user sees stale content.
Always start as a background task (run_in_background) so the server doesn't block the conversation. Do NOT use --headless unless asked — let marimo open the browser.
# Discover running servers
bash ${CLAUDE_SKILL_DIR}/marimo-pair/scripts/discover-servers.sh
# Execute code in the kernel (one-liner)
bash ${CLAUDE_SKILL_DIR}/marimo-pair/scripts/execute-code.sh -c "df.head()"
# Execute code (multiline — use heredoc to avoid shell escaping)
bash ${CLAUDE_SKILL_DIR}/marimo-pair/scripts/execute-code.sh <<'EOF'
import marimo._code_mode as cm
async with cm.get_context() as ctx:
cid = ctx.create_cell("x = 1")
ctx.run_cell(cid)
EOF
Use --port to target a specific server, --session for a specific notebook, --url for remote servers.
marimo._code_mode with async with cm.get_context() as ctx: to create/edit/delete cells and install packages. All ctx.* methods are synchronous — do NOT await them.create_cell and edit_cell are structural only — call ctx.run_cell(cid) to execute.ctx.install_packages(), not uv add or pip..py file directly while a session is running — the kernel owns it.marimo-pair/reference/finding-marimo.md — How to find and invoke the right marimo binarymarimo-pair/reference/gotchas.md — Cached module proxies and other trapsmarimo-pair/reference/rich-representations.md — Custom anywidgets, _display_(), Arrow IPC for large datamarimo-pair/reference/notebook-improvements.md — Setup cells, lifting functions, mo.persistent_cachemo.ui for interactive widgetsmo.sql(df, "SELECT * FROM df")mo.md("# Heading")1. Pre-execution validation:
# scripts: Validate notebook syntax and cell structure
scripts/check_notebook.sh notebook.py
Runs syntax check, marimo validation, and cell structure overview in one command.
2. Runtime errors: Export with outputs, then use notebook-debug skill:
# marimo: Export to ipynb with outputs for inspection
marimo export ipynb notebook.py -o __marimo__/notebook.ipynb --include-outputs
| Issue | Fix |
|-------|-----|
| Variable redefinition | Rename one variable or merge cells |
| Circular dependency | Break cycle by merging or restructuring |
| Missing return | Add return var, with trailing comma |
| Import not available | Ensure import cell returns the module |
For detailed patterns and advanced techniques, consult:
references/reactivity.md - DAG execution, variable rules, dependency detection patternsreferences/debugging.md - Error patterns, runtime debugging, environment-specific issuesreferences/widgets.md - Interactive UI components and mo.ui patternsreferences/sql.md - SQL cells and database integration techniquesmarimo-pair/reference/finding-marimo.md - How to find and invoke marimo across project typesmarimo-pair/reference/gotchas.md - Cached module proxies (e.g., polars + pyarrow mid-session)marimo-pair/reference/rich-representations.md - Custom anywidgets, Arrow IPC, _display_() protocolmarimo-pair/reference/notebook-improvements.md - Setup cells, lifting functions, mo.persistent_cacheWorking examples available in examples/:
examples/basic_notebook.py - Minimal marimo notebook structureexamples/data_analysis.py - Data loading, filtering, and visualization patternsexamples/interactive_widgets.py - Interactive UI component usageValidation and live-session utilities:
scripts/check_notebook.sh - Primary validation: syntax check, marimo validation, cell structure overviewscripts/get_cell_map.py - Extract cell metadata (invoked by check_notebook.sh)marimo-pair/scripts/discover-servers.sh - Find running marimo serversmarimo-pair/scripts/execute-code.sh - Execute code in a running marimo kernelnotebook-debug - Debugging executed ipynb files with tracebacks and output inspectionmarimo-pair/SKILL.md - Full marimo-pair protocol for live kernel interactiondevelopment
Build the meeting-level proxy-voting × ownership panel on the WRDS SGE grid — ISS N-PX fund votes reduced to (item × block) direction cells, joined to institutional and mutual-fund ownership. Use when working with risk.voteanalysis_npx, N-PX fund-level votes, ISS→CRSP fund linking, index/passive/active voting blocks, or a proxy-voting panel that needs ownership attached.
development
Use when "CRSP CIZ", "CRSP v2", "CRSP flat file format 2.0", "crsp.dsf_v2 / msf_v2", "StkDlySecurityData", "StkMthSecurityData", "StkSecurityInfoHist", "stocknames_v2", "DlyRet / MthRet / DlyPrc / MthPrc", "SHRCD or EXCHCD equivalent in new CRSP", "SIZ to CIZ migration", "CRSP data after 2024", "CRSP delisting returns", "CRSP cumulative adjustment factors", "CRSP index INDNO / INDFAM", or any CRSP stock/index query where the legacy SIZ column names no longer exist.
development
Use when linking or deduping datasets by entity name rather than a shared key — 'fuzzy match', 'fuzzy name matching', 'entity resolution', 'record linkage', 'match company/person names', 'dedupe entity names', 'name-based join', 'bridge identifiers' (CIK ↔ permno ↔ gvkey ↔ wficn ↔ EIN ↔ personid), or any use of char n-gram TF-IDF, cosine similarity on names, `sparse_dot_topn`, or RapidFuzz at scale.
development
Use when building a publication-quality table in Python — 'regression table', 'results table', 'summary statistics table', 'etable', 'coefplot', 'great_tables', 'GT', 'gt table', 'format a table for the paper', 'export table to LaTeX/HTML', significance stars, spanners, or column formatting for a table headed into a paper, slide deck, or notebook.