marimo-notebook by marimo-team/skills
npx skills add https://github.com/marimo-team/skills --skill marimo-notebookmarimo 使用 Python 创建笔记本,这与使用 JSON 的 Jupyter 不同。以下是一个示例笔记本:
# /// 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()
请注意,笔记本的结构是使用函数来表示单元格内容。每个单元格都使用 @app.cell 装饰器定义,函数的输入/输出就是单元格的输入/输出。marimo 通常会自动处理单元格之间的依赖关系。
# 以脚本形式运行(非交互式,用于测试)
uv run <notebook.py>
# 在浏览器中交互式运行
uv run marimo run <notebook.py>
# 交互式编辑
uv run marimo edit <notebook.py>
使用 mo.app_meta().mode == "script" 来检测 CLI 与交互模式:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
@app.cell
def _(mo):
is_script_mode = mo.app_meta().mode == "script"
return (is_script_mode,)
始终显示所有 UI 元素。 仅在脚本模式下更改数据源。
if not is_script_mode 条件语句中# 始终显示小部件
@app.cell
def _(ScatterWidget, mo):
scatter_widget = mo.ui.anywidget(ScatterWidget())
scatter_widget
return (scatter_widget,)
# 仅根据模式更改数据源
@app.cell
def _(is_script_mode, make_moons, scatter_widget, np, torch):
if is_script_mode:
# 使用合成数据进行测试
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:
# 在交互模式下使用小部件数据
X, y = scatter_widget.widget.data_as_X_y
# ... 处理数据 ...
return X_data, y_data, data_error
# 始终显示滑块 - 在两种模式下都使用它们的 .value 值
@app.cell
def _(mo):
lr_slider = mo.ui.slider(start=0.001, stop=0.1, value=0.01)
lr_slider
return (lr_slider,)
# 在脚本模式下自动运行,在交互模式下等待按钮
@app.cell
def _(is_script_mode, train_button, lr_slider, run_training, X_data, y_data):
if is_script_mode:
# 使用滑块默认值自动运行
results = run_training(X_data, y_data, lr=lr_slider.value)
else:
# 等待按钮点击
if train_button.value:
results = run_training(X_data, y_data, lr=lr_slider.value)
return (results,)
单元格之间的变量定义了笔记本在 99% 用例中的响应性。无需特殊的状态管理。不要在单元格之间改变对象(例如 my_list.append());应创建新对象。除非需要双向 UI 同步或累积回调状态,否则避免使用 mo.state()。详情请参阅 STATE.md。
if 语句保护单元格Marimo 的响应性意味着单元格只在其依赖项准备就绪时才会运行。不要添加不必要的保护:
# 错误 - if 语句阻止了图表的显示
@app.cell
def _(plt, training_results):
if training_results: # 错误 - 不要这样做
fig, ax = plt.subplots()
ax.plot(training_results['losses'])
fig
return
# 正确 - 让 marimo 处理依赖关系
@app.cell
def _(plt, training_results):
fig, ax = plt.subplots()
ax.plot(training_results['losses'])
fig
return
无论如何,在 training_results 有值之前,该单元格都不会运行。
除非要处理特定的、预期的异常,否则不要将代码包装在 try/except 块中。让错误自然地暴露出来。
# 错误 - 将错误隐藏在 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}"
# 正确 - 如果有问题就让它失败
@app.cell
def _(scatter_widget, np, torch):
X, y = scatter_widget.widget.data_as_X_y
X = np.array(X, dtype=np.float32)
# ...
仅在以下情况下使用 try/except:
Marimo 只渲染单元格的最终表达式。缩进或条件表达式不会被渲染:
# 错误 - 缩进表达式不会被渲染
@app.cell
def _(mo, condition):
if condition:
mo.md("This won't show!") # 错误 - 缩进
return
# 正确 - 最终表达式会被渲染
@app.cell
def _(mo, condition):
result = mo.md("Shown!") if condition else mo.md("Also shown!")
result # 这会渲染,因为它是最终表达式
return
通过 marimo edit --sandbox 创建的笔记本会自动将这些依赖项添加到文件顶部,但在创建笔记本时确保这些依赖项存在也是一个好习惯:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "marimo",
# "torch>=2.0.0",
# ]
# ///
在处理笔记本时,检查笔记本是否可以运行非常重要。这就是为什么 marimo 提供了一个 check 命令,它充当 linter 来查找常见错误。
uvx marimo check <notebook.py>
在将笔记本交还给用户之前,请确保检查了这些内容。
如果用户特别要求你使用 marimo 函数,你可以通过以下方式在本地查看文档:
uv --with marimo run python -c "import marimo as mo; help(mo.ui.form)"
默认情况下,marimo 会在你的笔记本中发现并执行测试。当可选的 pytest 依赖项存在时,marimo 会对完全由测试代码组成的单元格(即名称以 test_ 开头的函数)运行 pytest。如果用户要求你添加测试,请确保添加了 pytest 依赖项,并且有一个仅包含测试代码的单元格。
有关使用 pytest 进行测试的更多信息,请参阅 PYTEST.md
添加测试后,你可以从命令行在笔记本上运行 pytest 来执行测试。
pytest <notebook.py>
每周安装量
1.0K
代码仓库
GitHub 星标数
77
首次出现
2026年2月10日
安全审计
安装于
codex755
opencode713
claude-code706
github-copilot681
gemini-cli667
amp659
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.
if not is_script_mode conditionals# 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 for details.
if StatementsMarimo'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
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.
# 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
return
Notebooks 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",
# ]
# ///
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.
uvx 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)"
By default, marimo discovers and executes tests inside your notebook. When the optional pytest dependency is present, marimo runs pytest on cells that consist exclusively of test code - i.e. functions whose names start with test_. If the user asks you to add tests, make sure to add the pytest dependency is added and that there is a cell that contains only test code.
For more information on testing with pytest see PYTEST.md
Once tests are added, you can run pytest from the commandline on the notebook to run pytest.
pytest <notebook.py>
Weekly Installs
1.0K
Repository
GitHub Stars
77
First Seen
Feb 10, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex755
opencode713
claude-code706
github-copilot681
gemini-cli667
amp659
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
Flutter并发与数据管理指南:Isolate、JSON序列化与UI性能优化
980 周安装
小红书图片生成技能 - Markdown/HTML转精美小红书3:4截图,AI自动生成封面图
980 周安装
SRE工程师指南:核心工作流程、SLO定义、监控告警与自动化实践
981 周安装
Playwright 测试最佳实践指南 - 50+ 实战模式与 TypeScript/JavaScript 示例
981 周安装
Swift协议依赖注入测试:基于协议的DI模式实现可测试代码
982 周安装
maishou 买手技能:淘宝京东拼多多抖音快手全网比价,获取商品价格优惠券
983 周安装