关于 marimo-pair
marimo-pair 是一项用于操作实时 marimo 笔记本的技能,通过内核和 code-mode API 检查状态并持久化修改。它强调遵循响应式数据流,避免直接改写活动笔记本文件。
主要功能
- 01检查实时内核与单元格状态
- 02通过 code mode 创建和编辑单元格
- 03运行单元格及其响应式依赖
- 04管理笔记本依赖包与控件
- 05发现并选择笔记本会话
适用场景
- 01检查活动笔记本中的变量
- 02添加或修改持久化单元格
- 03通过 code mode 更改控件值
MCP 相关
该技能说明可通过 marimo MCP 执行代码和发现笔记本会话,也可使用随附脚本。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ marimo-team/ marimo-pair --skill marimo-pair安装后在 Claude Code 中输入/marimo-pair确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
reference/execution-context.mdfinding-marimo.mdgotchas.mdnotebook-improvements.mdrich-representations.mdscripts/discover-servers.shexecute-code.sh详细介绍
marimo 是一个响应式 Python 运行时,用于构建可复现的 Python 程序(marimo 笔记本)。单元格通过其定义和引用的变量相互连接。运行一个单元格时,会按数据流顺序重新执行依赖项。活动运行时保存内核命名空间、单元格状态和数据流图。笔记本(.py 文件)是内核在会话运行期间根据该状态写入的产物。
用户通过包含单元格、输出和小组件的笔记本 UI 与同一个运行时交互。
警告。活动运行时才是事实来源。 会话期间,SHOULD NOT 直接修改关联的 .py 文件。文件编辑不会传到活动内核或用户,并且内核可能会在保存时覆盖这些修改。请使用 marimo._code_mode(cm)更改笔记本。读取磁盘文件没有问题,但要获取当前单元格代码,优先使用 ctx.cells[...].code。
运行环境会报告此 SKILL.md 的绝对路径。即使当前工作目录是笔记本工作区,也请从该文件的父目录解析随附的 scripts/... 和 reference/... 路径。在命令示例中,将 /absolute/path/to/marimo-pair 替换为该目录。
必需的首次内核命令
每个代码模式会话都要以此专用命令开始:
bash /absolute/path/to/marimo-pair/scripts/execute-code.sh \
--url http://localhost:2718 \
-c "import marimo._code_mode as cm; help(cm)"
对每个内核都按以下顺序操作,包括只读任务:
- 运行一次检查命令。
- 等待
help(cm)成功输出。 - 然后在后续调用中使用
cm.get_context()或其他cmAPI。
检查命令成功之前,不要运行特定任务的 cm 代码。
连接到笔记本
使用随附的 execute-code.sh(位于报告的技能目录中)或 MCP(execute_code(...)),在正在运行的 marimo 内核中执行 Python。
execute-code.sh 始终需要 --url。如果用户提供了笔记本 URL,请直接针对该 URL 运行必需的检查:
bash /absolute/path/to/marimo-pair/scripts/execute-code.sh \
--url http://localhost:2718 \
-c "import marimo._code_mode as cm; help(cm)"
该命令成功后,通过 -c CODE、-(表示标准输入)或文件路径传入任务代码:
bash /absolute/path/to/marimo-pair/scripts/execute-code.sh \
--url http://localhost:2718 - <<'PY'
import marimo._code_mode as cm
async with cm.get_context() as ctx:
cid = ctx.create_cell("x = df.head()")
ctx.run_cell(cid)
PY
如果用户没有提供 URL,请查找或启动笔记本。使用 bash /absolute/path/to/marimo-pair/scripts/discover-servers.sh、MCP list_sessions() 或本地进程上下文查找正在运行的服务,并将其报告的 url 传给 --url。打开一个笔记本时,脚本会自动定位到它;打开多个笔记本时,请通过 --file 指定笔记本的文件键。
如果没有正在运行的服务且用户需要笔记本,请使用 --no-token 启动 marimo(不要使用 --headless),以便自动注册供发现。必须打开笔记本 UI,execute-code 才能定位到它。正确的调用方式取决于上下文(项目工具、全局安装、沙盒模式)。如果笔记本文件包含 PEP 723 # /// script 标头,则 MUST 使用 --sandbox 打开,否则 marimo 会忽略内联依赖项。完整的决策树请参阅 finding-marimo.md,有关选择器解析、脚本、MCP 和 shell 引号,请参阅 execution-context.md。
临时环境的作用范围
execute-code 会在 marimo 的临时环境中执行 Python:这是一个临时命名空间,其中包含内核全局变量的浅拷贝。笔记本变量可以通过名称访问,但每次调用结束后,新的顶层绑定和重新绑定都会被丢弃。对笔记本拥有的对象进行原地修改可能会保留,因为这些名称仍然引用实时对象。
每次调用都会报告临时环境中的标准输出和标准错误,以及由其触发运行的笔记本单元格(包括响应式后代)的控制台输出。
普通 Python
使用临时环境中的普通 Python 检查变量、采样数据、测试转换、探查 API、检查导入项以及读取小组件状态。
print(df.head())
x = 10
print(x)
这里的 df 来自笔记本全局变量,而 x 是临时环境中的局部绑定。x 仅在本次调用期间存在,不会添加到笔记本全局变量中。
使用 cm 持久化
顶层暂存区赋值和重新绑定都是临时的。要持久化工作,包括新变量,你 MUST 通过 marimo._code_mode
(cm)提交更改。
marimo._code_mode 是一个 PRIVATE、UNSTABLE 的 Agent API(注意开头的
下划线)。它的存在是为了让此类技能等工具能够从暂存区驱动实时内核。不要从笔记本单元格、库代码或用户会运行的任何内容中导入它——其方法可能会随 marimo 版本和内核而变化或消失。请将每个 import marimo._code_mode as cm 都视为仅用于暂存区。
打开代码模式上下文,以排队提交笔记本更改。
import marimo._code_mode as cm
async with cm.get_context() as ctx:
cid = ctx.create_cell("x = df.head()")
ctx.run_cell(cid)
暂存区支持顶层异步代码。直接使用 async with;
无需将其包装在 asyncio.run(...) 中,而且这样做可能会与
内核的事件循环冲突。
此代码块退出且新单元格运行后,x 就成为笔记本状态的一部分。后续
暂存区调用可以按名称读取 x。同一次暂存区调用中后续的代码
应读取 ctx.globals["x"],因为暂存区命名空间是在单元格运行之前复制的。
在上下文中,排队的变更方法是同步的。直接调用它们;不要使用 await。每次调用都会将一个操作排入队列,供 marimo 在上下文正常退出时应用。如果代码块引发异常,队列中的操作会被丢弃。
正常退出时,marimo 会应用包、验证并应用单元格结构变更、运行排队的单元格,然后可能运行依赖单元格。验证仅检查结构,因为排队单元格的运行仍可能出错。create_cell 和 edit_cell 只会更改单元格结构。执行请使用 run_cell。
create_cell 当前默认使用 hide_code=True,这会在 UI 中折叠代码编辑器。如果用户希望创建的单元格无需手动展开即可显示,请传入 hide_code=False。
marimo 规则
marimo 对笔记本代码施加了一套简明约定,以便将笔记本保持为有向无环图(DAG):
- 无循环——单元格之间不能形成循环依赖。
- 单元格之间不得重新定义公开名称——每个名称只能由一个单元格持有。
- 禁止通配符导入——
import *会妨碍对定义进行静态分析。
这些规则可以确保内核、UI 和保存的产物保持一致。
当 cm 提交单元格正文时,marimo 会解析其顶层定义和引用。公开名称会进入图中。以下划线 _ 开头的名称仅属于其所在单元格,其他单元格无法使用。如果 cm 的编辑违反了约定,marimo 会拒绝结构变更并返回验证错误。
笔记本的结构
笔记本是按顺序排列的单元格集合。ctx.cells 是文档视图,
ctx.graph 是数据流视图。
for cell in ctx.cells:
cell # .id, .code, .name, .config, .status, .errors
ctx.cells["setup"] # by name
ctx.cells[0] # by position
list(ctx.cells.keys()) # all IDs, in notebook order
单元格 ID 是不透明字符串,可以从笔记本中查询,也可以从 cm 的返回值中获取:
cid = ctx.create_cell("df = pd.read_csv('data.csv')")
print(cid) # e.g. 'Hbol'
也可以按 name 为单元格指定名称并引用。可以利用图来了解其在数据流中的作用。
for cid, impl in ctx.graph.cells.items():
impl # .defs, .refs (sets of public names)
ctx.graph.descendants(cid) # cells that re-run when this one changes
ctx.graph.ancestors(cid) # cells this one depends on
在 marimo 中,删除操作具有破坏性,因此删除前可以查询后代单元格,以了解删除的影响。
编写笔记本更改
图约定确保 marimo 能够运行和保存笔记本。仅通过这些检查并不能保证产物实用。提交的单元格仍应易读、可重新运行且可编辑。
进行持久化编辑时,应沿用笔记本现有的名称、导入、依赖项和 UI 模型。不要偷懒。避免采用只能通过 cm 验证、却会让笔记本变得脆弱的一次性变通方案。
单元格内容
提交属于该单元格的代码。
- 提交单元格内容——
create_cell和edit_cell接收的是单元格内容, 而不是保存文件中的@app.cell包装器。 - 替换前先读取——目前,其他编辑者可能会在暂存区调用之间更改单元格。
调用
edit_cell前,先从ctx.cells[...]读取当前内容,并提交完整的替换内容。 - 复用笔记本中的导入——如果
np已存在,请使用它或编辑所属的导入单元格。不要仅为绕过依赖图而添加import numpy as _np。 - 每个公开名称只定义一次——一个公开名称只能有一个所属单元格。
在另一个单元格中重新赋值会导致
Multiply-defined names错误;请编辑所属单元格,或为结果使用新名称。参见 gotchas.md。 - 有意运行单元格——
create_cell和edit_cell只会更改结构。需要执行单元格时,加入ctx.run_cell(...)队列。
单元格边界
单元格也是重新运行的边界。将开销较大或可复用的计算放在展示内容的上游,这样修改 UI 时成本更低。简单的、特定于展示的工作,则可与视图放在一起,以便阅读。
仅当组合属于 UI 时才使用 mo.vstack 和 mo.hstack。
叙述内容通常放在相邻的 Markdown 单元格中更易阅读。
优先使用 cm 管理更改
有 cm API 时请使用。避免直接编辑文件、使用 shell 执行包管理命令,以及仅存在于暂存区的状态,因为这些更改需要持久化。
- 不要编辑
.py文件——在实时会话中,切勿对笔记本文件使用Edit、Write或NotebookEdit。即使是小改动,也请使用ctx.edit_cell(...)。 - 通过
cm管理包——请使用ctx.packages.add()或ctx.packages.remove(),而不是直接使用uv或pip;对于不明显的依赖项变更,请先确认。 - 避免临时路径——除非工作本来就是临时的,否则持久化的单元格不应依赖
/tmp/...。 - 有意删除——删除单元格会移除它定义的全局变量。方便时可复用空单元格,并删除编辑后留下的空单元格。
UI 和小组件
修改对象前先检查对象。不同的 UI 对象需要通过不同的途径更新。
- 通过
cm设置mo.ui.*——在cm.get_context()内使用ctx.set_ui_value(element, value)。 - 直接设置 anywidget traitlets——同步的 traitlets 是 Python 属性,例如
widget.value = 5。
有关自定义可视化或交互式输出的设计,请参阅 rich-representations.md。
参考资料
- execution-context.md — 脚本、MCP、身份验证、启动和 shell 引号
- finding-marimo.md — 选择合适的 marimo 调用方式
- gotchas.md — 名称重新定义、缓存模块代理和笔记本陷阱
- rich-representations.md — 自定义小组件和可视化
- notebook-improvements.md — 改进现有笔记本