marimo

Use when working with marimo notebooks — creating, editing, debugging, converting from Jupyter, or pairing with a running marimo server.

6 stars

Best use case

marimo is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when working with marimo notebooks — creating, editing, debugging, converting from Jupyter, or pairing with a running marimo server.

Teams using marimo should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/marimo/SKILL.md --create-dirs "https://raw.githubusercontent.com/edwinhu/workflows/main/skills/marimo/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/marimo/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How marimo Compares

Feature / AgentmarimoStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when working with marimo notebooks — creating, editing, debugging, converting from Jupyter, or pairing with a running marimo server.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

## Contents

- [Editing and Verification Enforcement](#editing-and-verification-enforcement)
- [Key Concepts](#key-concepts)
- [Cell Structure](#cell-structure)
- [Editing Rules](#editing-rules)
- [Core CLI Commands](#core-cli-commands)
- [Export Commands](#export-commands)
- [Live Session (marimo-pair)](#live-session-marimo-pair)
- [Data and Visualization](#data-and-visualization)
- [Debugging Workflow](#debugging-workflow)
- [Common Issues](#common-issues)
- [Additional Resources](#additional-resources)

# Marimo Reactive Notebooks

Marimo is a reactive Python notebook where cells form a DAG and auto-execute on dependency changes. Notebooks are stored as pure `.py` files.

## Editing and Verification Enforcement

### IRON LAW #1: NEVER MODIFY CELL DECORATORS OR SIGNATURES

Only edit code INSIDE `@app.cell` function bodies. This is not negotiable.

**NEVER modify:**
- Cell decorators (`@app.cell`)
- Function signatures (`def _(deps):`)
- Return statements structure (trailing commas required)

**ALWAYS verify:**
- All used variables are in function parameters
- All created variables are in return statement
- Trailing comma for single returns: `return var,`

### IRON LAW #2: NO EXECUTION CLAIM WITHOUT OUTPUT VERIFICATION

Before claiming ANY marimo notebook works:
1. **VALIDATE** syntax and structure: `marimo check notebook.py`
2. **EXECUTE** with outputs: `marimo export ipynb notebook.py -o __marimo__/notebook.ipynb --include-outputs`
3. **VERIFY** using notebook-debug skill's verification checklist
4. **CLAIM** success only after verification passes

This is not negotiable. Skipping execution and output inspection is NOT HELPFUL — the user gets a notebook that fails when they open it.

### Marimo Facts

- `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.
- Reactivity propagates every edit through the DAG: a one-line change re-executes all dependent cells. Verifying only the edited cell misses downstream breakage — counterproductive on its own terms.
- Wrong dependencies or missing returns break reactivity silently: no error at edit time, only a NameError when a dependent cell runs. Validate that all used variables are in params AND all created variables are in returns.
- A variable created but not returned raises NameError in every cell that depends on it.
- Python treats `return var` as returning the bare value, which breaks unpacking — single returns require the trailing comma (`return var,`).

### Red Flags — STOP If About To:

- Edit a `@app.cell` decorator or `def _(...)` signature → STOP. Marimo manages these; edit only the function body.
- Claim done after only `marimo check` → STOP. Execution with `--include-outputs` is required.
- Claim the notebook works from reading the code → STOP. Reactive correctness shows only at runtime.
- Define a variable that another cell already defines → STOP. One variable = one cell.

### Editing Checklist

Before every marimo edit:

**Structure Validation:**
- [ ] Only edit code INSIDE `@app.cell` function bodies
- [ ] Do NOT modify decorators or signatures
- [ ] Verify all used variables are in function parameters
- [ ] Verify all created variables are in return statement
- [ ] Ensure trailing comma used for single returns
- [ ] Ensure no variable redefinitions across cells

**Syntax Validation:**
- [ ] Execute `marimo check notebook.py`
- [ ] Verify no syntax errors reported
- [ ] Verify no undefined variable warnings
- [ ] Verify no redefinition warnings

**Runtime Verification:**
- [ ] Execute with `marimo export ipynb notebook.py -o __marimo__/notebook.ipynb --include-outputs`
- [ ] Verify export succeeded (exit code 0)
- [ ] Verify output ipynb exists and is non-empty
- [ ] Apply notebook-debug verification checklist
- [ ] Verify no tracebacks in any cell
- [ ] Verify all cells executed (execution_count not null)
- [ ] Verify outputs match expectations

**Only after ALL checks pass:**
- [ ] Claim "notebook works"

### Gate Function: Marimo Verification

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.

## Key Concepts

- **Reactive execution**: Cells auto-update when dependencies change
- **No hidden state**: Each variable defined in exactly one cell
- **Pure Python**: `.py` files, version control friendly
- **Cell structure**: `@app.cell` decorator pattern

## Cell Structure

```python
import 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
```

## Editing Rules

- Edit code INSIDE `@app.cell` functions only
- Never modify cell decorators or function signatures
- Variables cannot be redefined across cells
- All used variables must be returned from their defining cell
- **Markdown cells: Always wrap `$` in backticks** - `mo.md("Cost: `$50`")` not `mo.md("Cost: $50")`

## Core CLI Commands

| 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 |

## Export Commands

```bash
# 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.

## Live Session (marimo-pair)

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`.

### Starting a Server

See `marimo-pair/reference/finding-marimo.md` for the full decision tree. Quick start:

```bash
# 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.

### Discovery and Execution

```bash
# 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.

### Key Concepts

- **Scratchpad execution**: Code runs in the kernel with all cell variables in scope, but nothing persists between calls. Use this to explore and validate.
- **Cell mutations**: Use `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.
- **Cells are not auto-executed**: `create_cell` and `edit_cell` are structural only — call `ctx.run_cell(cid)` to execute.
- **Install packages via `ctx.install_packages()`**, not `uv add` or `pip`.
- **NEVER write to the `.py` file directly while a session is running** — the kernel owns it.

### marimo-pair References

- `marimo-pair/reference/finding-marimo.md` — How to find and invoke the right marimo binary
- `marimo-pair/reference/gotchas.md` — Cached module proxies and other traps
- `marimo-pair/reference/rich-representations.md` — Custom anywidgets, `_display_()`, Arrow IPC for large data
- `marimo-pair/reference/notebook-improvements.md` — Setup cells, lifting functions, `mo.persistent_cache`

## Data and Visualization

- Prefer polars over pandas for performance
- Use `mo.ui` for interactive widgets
- SQL cells: `mo.sql(df, "SELECT * FROM df")`
- Display markdown: `mo.md("# Heading")`

## Debugging Workflow

**1. Pre-execution validation:**
```bash
# 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:
```bash
# marimo: Export to ipynb with outputs for inspection
marimo export ipynb notebook.py -o __marimo__/notebook.ipynb --include-outputs
```

## Common Issues

| 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 |

## Additional Resources

### Reference Files

For detailed patterns and advanced techniques, consult:
- **`references/reactivity.md`** - DAG execution, variable rules, dependency detection patterns
- **`references/debugging.md`** - Error patterns, runtime debugging, environment-specific issues
- **`references/widgets.md`** - Interactive UI components and mo.ui patterns
- **`references/sql.md`** - SQL cells and database integration techniques
- **`marimo-pair/reference/finding-marimo.md`** - How to find and invoke marimo across project types
- **`marimo-pair/reference/gotchas.md`** - Cached module proxies (e.g., polars + pyarrow mid-session)
- **`marimo-pair/reference/rich-representations.md`** - Custom anywidgets, Arrow IPC, `_display_()` protocol
- **`marimo-pair/reference/notebook-improvements.md`** - Setup cells, lifting functions, `mo.persistent_cache`

### Examples

Working examples available in `examples/`:
- **`examples/basic_notebook.py`** - Minimal marimo notebook structure
- **`examples/data_analysis.py`** - Data loading, filtering, and visualization patterns
- **`examples/interactive_widgets.py`** - Interactive UI component usage

### Scripts

Validation and live-session utilities:
- **`scripts/check_notebook.sh`** - Primary validation: syntax check, marimo validation, cell structure overview
- **`scripts/get_cell_map.py`** - Extract cell metadata (invoked by check_notebook.sh)
- **`marimo-pair/scripts/discover-servers.sh`** - Find running marimo servers
- **`marimo-pair/scripts/execute-code.sh`** - Execute code in a running marimo kernel

### Related Skills

- **`notebook-debug`** - Debugging executed ipynb files with tracebacks and output inspection
- **`marimo-pair/SKILL.md`** - Full marimo-pair protocol for live kernel interaction

Related Skills

marimo-serve

6
from edwinhu/workflows

Serve every marimo notebook in a project directory under one ASGI host with auto-discovery. Use when the user wants to browse multiple marimo apps at once (localhost, LAN, or tailnet) instead of running `marimo run` per file. Handles expose-on-tailnet via `tailscale serve`.

writing

6
from edwinhu/workflows

This skill should be used when the user asks to 'write a paper', 'start a writing project', 'draft an article', 'write about', 'brainstorm writing topics', 'gather sources for a paper', 'what should I write about', or needs the writing workflow entry point for any writing task.

writing-validate

6
from edwinhu/workflows

Validate draft sections cover all PRECIS claims before review.

writing-setup

6
from edwinhu/workflows

Internal skill for creating PRECIS.md, OUTLINE.md, and ACTIVE_WORKFLOW.md. Called after brainstorm sources are gathered.

writing-revise

6
from edwinhu/workflows

This skill should be used when the user asks to 'revise writing', 'fix review issues', 'polish draft', 'apply review feedback', 'complete writing workflow', or after /writing-review produces REVIEW.md with issues to fix.

writing-review

6
from edwinhu/workflows

Internal skill for hierarchical document review. Called by writing-validate after claim validation passes.

writing-precis-reviewer

6
from edwinhu/workflows

Internal skill used by writing-setup at exit gate. Dispatches a reviewer subagent to verify PRECIS.md quality before outlining. NOT user-facing.

writing-outline

6
from edwinhu/workflows

Internal skill for creating detailed section outlines. Called by /writing workflow after PRECIS and master OUTLINE are complete.

writing-outline-reviewer

6
from edwinhu/workflows

Internal skill used by writing-outline at exit gate. Dispatches a reviewer subagent to verify OUTLINE.md quality before drafting. NOT user-facing.

writing-lit-review

6
from edwinhu/workflows

Internal skill for literature review and source materialization. Called after brainstorm, before setup. NOT user-facing.

writing-legal

6
from edwinhu/workflows

Internal skill for academic legal writing. Loaded by /writing when style=legal. Based on Volokh's "Academic Legal Writing".

writing-handoff

6
from edwinhu/workflows

Create structured handoff document for writing workflow session pause/resume.