Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

6 Commits

Repository files navigation

marimo-opencode-skill

Prevent AI agents from breaking marimo notebooks with Python/Jupyter idioms.

Guardrails with Practical Coverage

This skill is designed to keep agents on track when building interactive notebooks (the standard use case).

It focuses on preventing DAG errors and broken UI reactivity while also covering the parts of marimo agents commonly get wrong in practice: UI patterns, SQL, state management, validation, deployment, and export. It still does not aim to document the entire Marimo API, and it does not cover advanced programmatic use cases like Cell.run().

Why?

LLMs are overfitted on Jupyter notebooks and imperative Python scripts. When they try to write marimo, they usually break the reactivity model by:

  1. Defining functions for cells (Marimo cells share the global scope; passing args is redundant and breaks the DAG).
  2. Using print() (Fails silently in marimo run / app mode; must use mo.md or mo.stat).
  3. Returning values (Cells don't "return" data; they define global variables).
  4. Mutating state (Reading and writing a variable in the same cell creates cycles).

This skill provides context prompts to force the model into "Marimo Mode."

Enforced Patterns

The skill actively prompts the agent to follow these rules:

CategoryRuleReason
VariablesGlobal, not ParameterCells are not functions. Don't write def process(df):. Just use df directly.
Outputmo.md() / mo.stat()print() outputs go to the console, not the UI, when running as an app.
Flow Controlmo.stop(), not raiseUse mo.stop() to conditionally halt execution without crashing the app UI.
ReactivitySplit Definition & ReadIf you define slider = mo.ui.slider(), you cannot read slider.value in the same cell.
LocalsUse _ prefix_var stays local to the cell. Anything else becomes a global variable in the DAG.
CallbacksPrefer reactivity over on_changeMost notebooks should read .value in downstream cells; if you do use callbacks, marimo passes the raw value (int/str), not a Jupyter-style change dict.
SQLDirect DataFramemo.sql() returns a DataFrame directly. Do not try to access .value.
FormsCheck for Noneform.value is None until submitted. Guard against this with mo.stop().
MutationMutate LocallyDo not mutate a global variable (like a DataFrame) in a different cell than where it was defined.

About

Marimo skill to help opencode agents create proper interactive marimo notebooks

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors