Install any skill in seconds. Free to start, no credit card required.
Get Started Free →marimo ノートブックを正しいフォーマットでPythonファイルに作成するスキル。 「marimoノートブック作成」「インタラクティブノートブック」「Pythonノートブック」等のリクエストで発動。
.claude/skills/minicoohei-marimo-notebook/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✗→✓ | ▲ Improved | 87% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 13% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 23% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 5% | 0% |
「marimoノートブック」「インタラクティブノートブック」「Pythonノートブック」「marimo」
bash# Run as script (non-interactive, for testing) uv run <notebook.py> # Run interactively in browser uv run marimo run <notebook.py> # Edit interactively uv run marimo edit <notebook.py>
Use mo.app_meta().mode == "script" to detect CLI vs interactive:
python@app.cell def _(mo): is_script_mode = mo.app_meta().mode == "script" return (is_script_mode,)
Show all UI elements always. Only change the data source in script mode.
if not is_script_mode conditionalspython# Always show the widget @app.cell def _(ScatterWidget, mo): scatter_widget = mo.ui.anywidget(ScatterWidget()) scatter_widget return (scatter_widget,) # Only change data source based on mode @app.cell def _(is_script_mode, make_moons, scatter_widget, np, torch): if is_script_mode: # Use synthetic data for testing X, y = make_moons(n_samples=200, noise=0.2) X_data = torch.tensor(X, dtype=torch.float32) y_data = torch.tensor(y) data_error = None else: # Use widget data in interactive mode X, y = scatter_widget.widget.data_as_X_y # ... process data ... return X_data, y_data, data_error # Always show sliders - use their .value in both modes @app.cell def _(mo): lr_slider = mo.ui.slider(start=0.001, stop=0.1, value=0.01) lr_slider return (lr_slider,) # Auto-run in script mode, wait for button in interactive @app.cell def _(is_script_mode, train_button, lr_slider, run_training, X_data, y_data): if is_script_mode: # Auto-run with slider defaults results = run_training(X_data, y_data, lr=lr_slider.value) else: # Wait for button click if train_button.value: results = run_training(X_data, y_data, lr=lr_slider.value) return (results,)
if StatementsMarimo's reactivity means cells only run when their dependencies are ready. Don't add unnecessary guards:
python# BAD - the if statement prevents the chart from showing @app.cell def _(plt, training_results): if training_results: # WRONG - don't do this fig, ax = plt.subplots() ax.plot(training_results['losses']) fig return # GOOD - let marimo handle the dependency @app.cell def _(plt, training_results): fig, ax = plt.subplots() ax.plot(training_results['losses']) fig return
The cell won't run until training_results has a value anyway.
Don't wrap code in try/except blocks unless you're handling a specific, expected exception. Let errors surface naturally.
python# BAD - hiding errors behind try/except @app.cell def _(scatter_widget, np, torch): try: X, y = scatter_widget.widget.data_as_X_y X = np.array(X, dtype=np.float32) # ... except Exception as e: return None, None, f"Error: {e}" # GOOD - let it fail if something is wrong @app.cell def _(scatter_widget, np, torch): X, y = scatter_widget.widget.data_as_X_y X = np.array(X, dtype=np.float32) # ...
Only use try/except when:
Marimo only renders the final expression of a cell. Indented or conditional expressions won't render:
python# BAD - indented expression won't render @app.cell def _(mo, condition): if condition: mo.md("This won't show!") # WRONG - indented return # GOOD - final expression renders @app.cell def _(mo, condition): result = mo.md("Shown!") if condition else mo.md("Also shown!") result # This renders because it's the final expression return
Variables in for loops that would conflict across cells need underscore prefix:
python# Use _name, _model to make them cell-private for _name, _model in items: ...
python# /// script # requires-python = ">=3.12" # dependencies = [ # "marimo", # "torch>=2.0.0", # ] # ///
Use pathlib.Path for file path operations instead of os.path:
python# GOOD - use pathlib from pathlib import Path data_dir = Path(tempfile.mkdtemp()) parquet_file = data_dir / "data.parquet" # BAD - avoid os.path import os parquet_file = os.path.join(temp_dir, "data.parquet")
When working on a notebook it is important to check if the notebook can run. That's why marimo provides a check command that acts as a linter to find common mistakes.
bashuvx marimo check <notebook.py>
Make sure these are checked before handing a notebook back to the user.
If the user specifically wants you to use a marimo function, you can locally check the docs via:
uv --with marimo run python -c "import marimo as mo; help(mo.ui.form)"| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-16 | fail→pass | 9,069 | 7,536 | -17% | 1 | 1 | 0% | 1,716 | 3,210 | +87% | 0 | 0 | — |
case-01 | fail→pass | 27,820 | 22,607 | -19% | 1 | 1 | 0% | 6,205 | 6,983 | +13% | 0 | 0 | — |
case-02 | fail→pass | 16,829 | 10,651 | -37% | 1 | 1 | 0% | 2,925 | 3,601 | +23% | 0 | 0 | — |
case-03 | fail→pass | 16,719 | 17,997 | +8% | 1 | 1 | 0% | 3,627 | 5,730 | +58% | 0 | 0 | — |
case-04 | pass→pass | 10,213 | 2,994 | -71% | 1 | 1 | 0% | 1,782 | 2,171 | +22% | 0 | 0 | — |
case-05 | pass→pass | 2,754 | 1,472 | -47% | 1 | 1 | 0% | 471 | 1,926 | +309% | 0 | 0 | — |
case-06 | pass→pass | 4,260 | 1,815 | -57% | 1 | 1 | 0% | 666 | 1,938 | +191% | 0 | 0 | — |
case-07 | fail→pass | 11,337 | 2,091 | -82% | 1 | 1 | 0% | 1,909 | 2,003 | +5% | 0 | 0 | — |
case-08 | fail→pass | 5,735 | 1,404 | -76% | 1 | 1 | 0% | 1,019 | 1,908 | +87% | 0 | 0 | — |
case-09 | pass→pass | 10,490 | 4,610 | -56% | 1 | 1 | 0% | 1,591 | 2,456 | +54% | 0 | 0 | — |
case-10 | pass→pass | 13,274 | 7,839 | -41% | 1 | 1 | 0% | 2,269 | 2,938 | +29% | 0 | 0 | — |
case-11 | pass→pass | 10,647 | 5,424 | -49% | 1 | 1 | 0% | 1,720 | 2,707 | +57% | 0 | 0 | — |
case-12 | pass→pass | 9,604 | 4,658 | -51% | 1 | 1 | 0% | 1,665 | 2,426 | +46% | 0 | 0 | — |
case-13 | pass→pass | 4,294 | 3,094 | -28% | 1 | 1 | 0% | 788 | 2,189 | +178% | 0 | 0 | — |
case-14 | pass→pass | 6,339 | 3,932 | -38% | 1 | 1 | 0% | 1,203 | 2,386 | +98% | 0 | 0 | — |
case-15 | pass→pass | 8,391 | 4,515 | -46% | 1 | 1 | 0% | 1,540 | 2,543 | +65% | 0 | 0 | — |
case-17 | pass→pass | 10,073 | 7,633 | -24% | 1 | 1 | 0% | 1,736 | 2,993 | +72% | 0 | 0 | — |
case-18 | pass→pass | 8,650 | 7,379 | -15% | 1 | 1 | 0% | 1,715 | 3,100 | +81% | 0 | 0 | — |
case-19 | pass→pass | 11,308 | 7,578 | -33% | 1 | 1 | 0% | 2,010 | 2,902 | +44% | 0 | 0 | — |
case-20 | pass→pass | 4,202 | 4,914 | +17% | 1 | 1 | 0% | 680 | 2,598 | +282% | 0 | 0 | — |
case-21 | pass→pass | 11,229 | 8,030 | -28% | 1 | 1 | 0% | 2,175 | 3,198 | +47% | 0 | 0 | — |
case-22 | fail→pass | 14,999 | 9,297 | -38% | 1 | 1 | 0% | 2,254 | 2,849 | +26% | 0 | 0 | — |
case-23 | pass→pass | 8,069 | 3,314 | -59% | 1 | 1 | 0% | 1,414 | 2,294 | +62% | 0 | 0 | — |
case-24 | pass→pass | 11,330 | 4,688 | -59% | 1 | 1 | 0% | 1,928 | 2,589 | +34% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +29 percentage points is the difference between those two pass rates over the 24 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.