add-molab-badge
Add "Open in molab" badge(s) linking to marimo notebooks. Works with READMEs, docs, websites, or any markdown/HTML target.
Write a marimo notebook in a Python file in the right format.
$ npx -y skills add marimo-team/skills --skill marimo-notebook --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/marimo-notebookContext preview
The summary Claude sees to decide when to auto-load this skill.
Write a marimo notebook in a Python file in the right format.
name: marimo-notebook description: Write a marimo notebook in a Python file in the right format.
marimo uses Python to create notebooks, unlike Jupyter which uses JSON. Here's an example notebook:
# /// script
# dependencies = [
# "marimo",
# "numpy==2.4.3",
# ]
# requires-python = ">=3.14"
# ///
import marimo
__generated_with = "0.20.4"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
import numpy as np
return mo, np
@app.cell
def _():
print("hello world")
return
@app.cell
def _(np, slider):
np.array([1,2,3]) + slider.value
return
@app.cell
def _(mo):
slider = mo.ui.slider(1, 10, 1, label="number to add")
slider
return (slider,)
@app.cell
def _():
return
if __name__ == "__main__":
app.run()Notice how the notebook is structured with functions can represent cell contents. Each cell is defined with the `@app.cell` decorator and the inputs/outputs of the function are the inputs/outputs of the cell. marimo usually takes care of the dependencies between cells automatically.
# 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:
@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.
# 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,)Variables between cells define the reactivity of the notebook for 99% of the use-cases out there. No special state management needed. Don't mutate objects across cells (e.g., `my_list.append()`); create new objects instead. Avoid `mo.state()` unless you need bidirectional UI sync or accumulated callback state. See [STATE.md](references/STATE.md) for details.
Marimo's reactivity means cells only run when their dependencies are ready. Don't add unnecessary guards:
# 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
returnThe 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.
# 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:
# 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
returnNotebooks created via `marimo edit --sandbox` have these dependencies added to the top of the file automatically but it is a good practice to make sure these exist when creating a notebook too:
# /// script # requires-python = ">=3.12" # dependencies = [ # "marimo", # "torch>=2.0.0", # ] # ///
This repository contains skills for use with marimo. Install these skills with: The benefit of npx skills is that it supports many agents. So you can do things like: We welcome feedback: issues and pull requests are welcome.
Add "Open in molab" badge(s) linking to marimo notebooks. Works with READMEs, docs, websites, or any markdown/HTML target.
Make a demo of a research paper in a marimo notebook fully automatically without extra user input.
Implement a research paper in a marimo notebook fully automatically without extra user input.
Implement a research paper as an interactive marimo notebook together with the user. Start by understanding what the user wants to explore, fetch the paper via…
Convert a Jupyter notebook (.ipynb) to a marimo notebook (.py).