Python Notebooks: Marimo, Reactivity, and Runtime

Marimo reactivity, variable rules, imports and dependencies, and Pyodide runtime constraints.

This section describes how Python code executes inside Boardflare workbooks, including the Marimo reactive model, interactive UI controls for App mode, imports and dependencies, and the Pyodide WebAssembly environment.

The Marimo Reactive Model

Boardflare uses Marimo as its notebook engine. Unlike traditional Jupyter notebooks, execution order is determined by a Directed Acyclic Graph (DAG) of variable references, not top-to-bottom cell order.

Core Authoring Rules

  1. One Definition Per Variable: A global variable name can be defined in at most one cell. If two cells define the same variable name (e.g. x = 10 in Cell 1 and x = 20 in Cell 2), Marimo halts both with a MultipleDefinitionError. To reuse intermediate variable names without conflicts, prefix them with an underscore (e.g. _temp = ...) or encapsulate logic in local functions.

  2. Reactivity: When a cell changes its output or when an Anywidget traitlet updates (such as inputs receiving a new workbook snapshot), Marimo automatically recalculates all downstream cells that reference those variables.

  3. Keep Widgets Displayed: The Anywidget models for inputs = bf.inputs(...) and publication = bf.publish(...) must be displayed as the return value of a cell (e.g. putting inputs on the final line of the cell). Displaying them maintains the live communications channel with the host.

  4. Cell Functions: Functions that contain application logic or helper code can be decorated with @app.function or declared inside ordinary @app.cell functions.

  5. Replacement Models: When an edit re-creates bf.inputs(...), the new model becomes authoritative only after its initial workbook snapshot succeeds. If the snapshot is invalid, the previous working model stays active.

  6. Durable and Live State: The notebook source is durable: it is saved with the workbook. Workbook input snapshots, published outputs, published functions, widget state, and in-flight function calls are live-session state. Running the notebook rebuilds them, and they do not survive a restart or reset.


Interactive UI and App Mode Authoring

In App Mode, Boardflare hides all Python code cells and displays only rendered UI controls, markdown text, charts, and application widgets in a clean, full-pane task-pane interface.

Marimo UI Elements (mo.ui)

Marimo provides native UI controls that bind directly to reactive variables. Import Marimo as import marimo as mo:

import marimo as mo

# Declare interactive controls
scenario_dropdown = mo.ui.dropdown(
    options=["Baseline", "Optimistic", "Stress Case"],
    value="Baseline",
    label="Scenario:",
)
discount_slider = mo.ui.slider(
    start=0.0,
    stop=0.5,
    step=0.01,
    value=0.10,
    label="Discount Rate:",
)

# Display controls together in the cell
mo.hstack([scenario_dropdown, discount_slider])

Downstream cells access the current value of the control via .value:

selected_scenario = scenario_dropdown.value
discount_rate = discount_slider.value

# Calculations update automatically when the user interacts with the control
adjusted_revenue = base_revenue * (1 - discount_rate)

Common UI Components

  • Inputs: mo.ui.text, mo.ui.number, mo.ui.slider, mo.ui.date, mo.ui.checkbox, mo.ui.switch.
  • Selectors: mo.ui.dropdown, mo.ui.radio, mo.ui.multiselect.
  • Tabular Data: mo.ui.table(df, selection="single" | "multi").
  • Layout & Structure: mo.vstack([...]) (vertical column), mo.hstack([...]) (horizontal row), mo.accordion({...}), mo.tabs({...}).
  • Narrative & Formatting: mo.md("# Heading\nYour narrative here...") formats rich Markdown text.
  • KPI Metrics: mo.stat(value="$125,000", label="Total Revenue", caption="+12% YoY").

Visualizations

Charts created with matplotlib, seaborn, or plotly render directly in both Edit and App modes: - Plotly: Return the figure object as the final expression of a cell. - Matplotlib / Seaborn: Return the fig or ax object. Do not call plt.show().


Imports and Dependencies

Notebooks have no PEP 723 # /// script block. Do not write one: the runtime injects its own block (pandas and the boardflare wheel) when it loads the notebook, and notebook headers start at import marimo:

import marimo

app = marimo.App(width="medium")

Just import what you need. Imports resolve from the Pyodide lockfile, which includes the pre-bundled companion packages, plus the Python standard library. Nothing is fetched from PyPI.

Why no declarations: Marimo sends every declared dependency that is not already loaded to micropip.install, which fetches from PyPI and fails under the notebook’s connect-src 'self' policy. A declaration adds nothing for packages the lockfile already provides, and only adds a failure path for packages it does not.


The Pyodide WebAssembly Runtime

Boardflare executes Python in the user’s browser using Pyodide (Python compiled to WebAssembly).

Security and Network Isolation

  • Zero-Network Sandbox: The notebook execution iframe runs under a strict Content Security Policy (connect-src 'self'). It has no access to external internet addresses, raw sockets, or local filesystem resources.
  • No Runtime Pip Installation: Dynamic package installation at runtime via pip or network fetching is disabled. Packages cannot be installed at runtime; imports resolve from the Pyodide lockfile, which includes the pre-bundled companion packages.

Pre-bundled Companion Packages

To provide rich analytical and data capabilities without external network access, the Boardflare runtime pre-bundles 15 pure-Python companion packages directly into the Pyodide image lockfile:

Package Version Primary Import Name(s) Description
babel 2.18.0 babel Internationalization and formatting utilities
chardet 7.6.0 chardet Universal character encoding detector
colorcet 3.2.1 colorcet Perceptually uniform colormaps
defusedxml 0.7.1 defusedxml XML bomb and entity expansion protection
et-xmlfile 2.0.0 et_xmlfile Low-memory XML generator for OpenPyXL
humanize 4.16.0 humanize Human-readable numbers, times, and file sizes
intervaltree 3.2.1 intervaltree Interval tree data structures
jmespath 1.1.0 jmespath Declarative JSON query language
openpyxl 3.0.9 openpyxl Excel spreadsheet reading and writing
plotly 7.1.0 plotly, _plotly_utils Interactive visualization library
python-slugify 9.0.0 slugify String slugification library
seaborn 0.13.2 seaborn Statistical data visualization
tabulate 0.10.0 tabulate Pretty-print tabular data
text-unidecode 1.3 text_unidecode Unicode to ASCII transliteration
textdistance 4.6.3 textdistance Distance and similarity algorithms between sequences

These packages can be imported immediately in any notebook without installation:

import humanize
import plotly.express as px
import seaborn as sns

Verified Package List

Only packages available in Pyodide or included on the companion list can be imported. Attempting to import an unavailable package raises ModuleNotFoundError.