Architecture and Runtime

Understand the Excel shared runtime, cross-origin marimo/Pyodide notebook, Spreadsheet Bridge, Anywidget capabilities, worksheet functions, lifecycle, and source persistence.

This page is for developers, security reviewers, and advanced workbook authors who need the implementation model. For normal workbook use, start with Getting Started and Working with Excel.

Boardflare gives substantial Python work a reactive marimo notebook while keeping Excel connected as the workbook-data, assumptions, review, and delivery surface. The shipping runtime uses a stock marimo WebAssembly export rather than a Boardflare fork. Boardflare owns the host integration around that runtime.

Complete runtime topology

flowchart TB
    subgraph Excel[Excel host]
        WB[Workbook cells / ranges / names]
        XML[Workbook Custom XML\nnotebook source + opening mode]
        CF[Excel custom functions\nBF.OUTPUT / BF.FUNCTION / BOARDFLARE.EXEC]
        SR[Long-lived shared runtime]
    end

    subgraph Parent[Boardflare parent application]
        Tabs[Python tabs / task-pane UI]
        Host[NotebookSession + NotebookSurface]
        Bridge[Spreadsheet Bridge\nExcel driver]
        Store[Live notebook store]
    end

    subgraph Child[Separate-origin notebook iframe]
        Marimo[Stock marimo WebAssembly export]
        Pyodide[Pyodide / browser CPython]
        Inputs[bf.inputs Anywidget model]
        Publish[bf.publish Anywidget model]
    end

    WB <--> Bridge
    XML <--> Host
    CF <--> SR
    SR --> Tabs
    Tabs --> Host
    Host <--> Store
    Host <-->|validated MessagePorts| Marimo
    Marimo --> Pyodide
    Pyodide --> Inputs
    Pyodide --> Publish
    Inputs <-->|input capability| Host
    Publish <-->|outputs capability| Host
    Host <--> Bridge
    Store <--> CF

The important boundary is that notebook Python does not receive an unrestricted Office.js workbook object. Workbook integration is exposed through the public boardflare package and explicit host capabilities.

Responsibility boundaries

Layer Owns
Excel / spreadsheet host Workbook cells, formulas, defined names, Custom XML, host events
Excel shared runtime Long-lived JavaScript runtime used by the task pane and custom functions
Spreadsheet Bridge Host-neutral workbook capability contract and Excel/Univer drivers
Boardflare notebook host Session startup, source persistence, input/output capabilities, worksheet registry integration
marimo Notebook editing, serialization, dependency graph, reactive execution, notebook UI primitives
Pyodide Browser/WebAssembly CPython and compatible package runtime
boardflare Python package Public bf.ref, bf.inputs, and bf.publish interfaces plus Anywidget models
Notebook worksheet adapters Streaming BF.OUTPUT and BF.FUNCTION integration with the live publication registry
Legacy execution path BOARDFLARE.EXEC, workbook-stored legacy functions, and the runpy worker

Boardflare deliberately does not depend on marimo private runtime modules, mutate minified marimo internals, replace the kernel worker, or persist a second executable Python catalog for notebook functions.

Calculation and authentication are separate lifecycles

The Notebook component has calculation semantics even when it is not visible. In Excel, the notebook runtime is kept mounted across task-pane navigation and is allowed to mount while Office authentication is still resolving.

flowchart LR
    Start[Excel starts Boardflare shared runtime]
    Calc[Mount notebook calculation runtime]
    Auth[Resolve Office SSO]
    Source[Restore saved source / starter]
    Run[Run marimo + Pyodide]
    Pub[bf.inputs / bf.publish connect]
    Formulas[BF.OUTPUT / BF.FUNCTION resolve]
    Org[Organization tenant + token]
    Personal[Personal / anonymous / unresolved]
    AIOn[Notebook AI enabled]
    AIOff[Notebook AI disabled]

    Start --> Calc
    Start --> Auth
    Calc --> Source --> Run --> Pub --> Formulas
    Auth --> Org --> AIOn
    Auth --> Personal --> AIOff

This separation is intentional. A workbook that only needs saved BF.OUTPUT() or BF.FUNCTION() formulas can calculate without waiting for the sign-in UI. Office identity controls Notebook AI eligibility; it is not a prerequisite for the core calculation runtime.

Startup lifecycle

A fresh NotebookSession creates a session ID, secure nonce, source capability, and child iframe. Startup then follows this sequence:

sequenceDiagram
    participant Excel
    participant Parent as Boardflare parent
    participant Child as Notebook child
    participant Marimo
    participant Python as Pyodide / Python

    Excel->>Parent: Start shared runtime / mount Notebook
    Parent->>Child: Load separate-origin notebook child
    Child->>Parent: Request source capability\n(session + nonce + protocol + port)
    Parent-->>Child: Transfer source MessagePort
    Child->>Parent: source.initialize
    Parent-->>Child: Saved source or no saved source + opening mode
    Child->>Child: Fall back to bundled starter when needed
    Child->>Marimo: Mount stock export in Edit or App presentation
    Marimo->>Python: Start browser Python runtime
    Python->>Parent: bf.inputs capability connection
    Parent-->>Python: Initial workbook snapshot
    Python->>Parent: bf.publish prepare / claim
    Parent-->>Python: Publication acknowledged

The notebook frontend has a 90-second startup timeout. During normal startup, streaming Excel formulas can remain in Excel’s native #BUSY! state until a registry is available or startup fails terminally.

Workbook inputs enter marimo’s reactive graph

bf.inputs() declares explicit workbook dependencies:

import boardflare as bf

inputs = bf.inputs(
    sales=bf.ref("Sales!A1:D20", headers=True),
    scenario="Assumptions!B2",
)
inputs

The returned Anywidget must remain displayed because its model owns the host capability connection.

sequenceDiagram
    participant Cell as Notebook cell
    participant Widget as bf.inputs model
    participant Host as Boardflare host
    participant Excel

    Cell->>Widget: Declare named references
    Widget->>Host: Connect input capability
    Host->>Excel: Resolve references + read values
    Excel-->>Host: Values + dependency ranges
    Host-->>Widget: Atomic input snapshot
    Widget-->>Cell: Traits become ready
    Cell->>Cell: marimo reruns dependents
    Excel-->>Host: Relevant workbook change
    Host->>Host: Debounce + re-resolve bindings
    Host-->>Widget: Replacement atomic snapshot
    Widget-->>Cell: Reactive update

Before the first workbook snapshot is ready, reading a required input stops the current marimo cell and descendants. This prevents a startup placeholder from becoming a valid published calculation.

A replacement input model becomes authoritative only after its initial snapshot succeeds, so an invalid replacement does not immediately destroy the prior working generation.

Published outputs and functions

bf.publish() is the notebook’s explicit worksheet-facing registry:

def discount(price, rate=0.0):
    return float(price) * (1 - float(rate))

publication = bf.publish(
    outputs={"summary": summary},
    functions={"discount": discount},
)
publication

The output model first prepares against the host’s workbook date system, converts values in Python, and only then claims the registry.

sequenceDiagram
    participant Widget as bf.publish model
    participant Host as Boardflare host
    participant Python

    Widget->>Host: outputs.prepare
    Host-->>Widget: outputs.prepared(dateSystem)
    Widget->>Python: Configure Excel value conversion
    Python-->>Widget: Converted values + function metadata
    Widget->>Host: outputs.claim
    Host-->>Widget: outputs.ack

A successful claim atomically replaces the prior value/function generation. Failed validation or conversion leaves the prior successful generation active.

Live worksheet invocation

BF.OUTPUT() subscribes to a published value. BF.FUNCTION() invokes a retained Python callable through the active publication model.

sequenceDiagram
    participant Excel
    participant CF as BF.FUNCTION
    participant Store as Shared-runtime store
    participant Host as Outputs capability
    participant Widget as bf.publish model
    participant Python

    Excel->>CF: =BF.FUNCTION("discount", A1, B1)
    CF->>Store: Subscribe + validate name/arity
    Store->>Host: Queue invocation
    Host->>Widget: Function request batch
    Widget->>Python: Invoke retained callable
    Python-->>Widget: Converted result / bounded error
    Widget-->>Host: Function result
    Host-->>Store: Accept only active session/generation/request
    Store-->>CF: Result
    CF-->>Excel: Resolve streaming formula

Replacing the publication generation reinvokes active function subscriptions against the replacement registry. Formula cancellation removes the subscription and sends best-effort cancellation to Python. Asynchronous Python tasks can be canceled; synchronous Python code already blocking the kernel cannot be force-preempted.

Published consumer references

The publication model also receives active worksheet consumer references. The widget can show which formulas use each output or function, and Python can inspect the same mapping through publication.consumers.

In Excel, references follow streaming subscription lifetimes and identify the formula anchor cell. In the standalone Univer host, Boardflare indexes formula cells by scanning and rescanning the used range because that host exposes a different custom-function lifecycle.

Notebook formulas and legacy formulas are separate

The add-in intentionally retains two independent worksheet execution systems:

flowchart LR
    subgraph Notebook[Notebook path]
        N1[BF.OUTPUT / BF.FUNCTION]
        N2[Lightweight shared-runtime adapters]
        N3[Live notebook store]
        N4[bf.publish Anywidget]
        N5[Retained Python values / callables]
        N1 --> N2 --> N3 --> N4 --> N5
    end

    subgraph Legacy[Legacy path]
        L1[Workbook Name Manager LAMBDA]
        L2[BOARDFLARE.EXEC]
        L3[Legacy runpy worker]
        L4[Workbook-stored function object]
        L1 --> L2 --> L3 --> L4
    end

Notebook functions are not registered in Excel Name Manager and are not persisted as an executable function catalog. The legacy Editor does register Name Manager LAMBDAs that call BOARDFLARE.EXEC. A notebook bundle failure must not prevent the established BOARDFLARE.EXEC association from remaining available.

See Legacy Functions Editor for the compatibility workflow.

Workbook source lifecycle

Boardflare persists notebook source, not a frozen Python interpreter.

stateDiagram-v2
    [*] --> BundledStarter: no saved notebook
    [*] --> SavedWorkbook: saved notebook exists
    BundledStarter --> SavedWorkbook: marimo Save + verified persistence
    SavedWorkbook --> StagedUpload: upload .py
    StagedUpload --> SavedWorkbook: marimo Save + verified persistence
    StagedUpload --> SavedWorkbook: Restore saved notebook after startup failure
    SavedWorkbook --> BundledStarter: Reset saved notebook

An uploaded .py file is staged in memory and starts a new Edit session. It does not overwrite workbook Custom XML until marimo Save reaches Boardflare and persistence verifies successfully. That distinction is why a broken upload can be discarded without deleting the last saved notebook.

Download flushes FileStore writes that marimo has already submitted and exports the latest source acknowledged by Boardflare. It cannot serialize editor changes that marimo has never submitted through Save.

Save and persistence sequence

sequenceDiagram
    participant User
    participant Marimo
    participant FileStore as Boardflare FileStore
    participant Source as Source capability
    participant XML as Workbook Custom XML

    User->>Marimo: Save
    Marimo->>Marimo: Serialize current notebook source
    Marimo->>FileStore: saveFile(source)
    FileStore->>FileStore: Queue save callback
    FileStore->>Source: source.save(source, opening mode)
    Source->>XML: Write notebook record
    Source->>XML: Read record back
    XML-->>Source: Stored source + metadata
    Source->>Source: Verify source/hash/mode
    alt verification succeeds
        Source-->>FileStore: Acknowledge persisted source
        FileStore-->>User: Boardflare status = Saved
    else write/read-back fails
        Source->>XML: Attempt previous-value rollback
        Source-->>FileStore: Save failure
        FileStore-->>User: Boardflare status = Save failed
    end

Marimo’s own clean/dirty state is not proof that the asynchronous workbook write completed. The Boardflare save status is authoritative for durable workbook persistence.

Excel Custom XML record

Excel stores one Boardflare notebook Custom XML part. The version-1 record contains notebook source, a SHA-256 digest, the saved Edit/App opening preference (edit/run internally), a timestamp, and the schema version.

Current storage boundaries are:

Item Limit
Notebook source 200,000 UTF-8 bytes
Complete notebook XML 1,000,000 bytes

Live input snapshots, output values, Python function objects, Anywidget generations, worksheet consumer references, and pending function calls are not serialized into the workbook. They are reconstructed by running the saved source.

Spreadsheet Bridge and the standalone demo

Notebook code does not call Office.js directly. Host-specific workbook operations live behind @boardflare/spreadsheet-bridge.

flowchart TB
    Notebook[Boardflare notebook integration] --> Bridge[Spreadsheet Bridge]
    Bridge --> ExcelDriver[Excel driver]
    Bridge --> UniverDriver[Univer driver]
    ExcelDriver --> Office[Office.js / Excel workbook]
    UniverDriver --> Univer[Univer browser workbook]

The standalone website demo shares the source/input/output concepts but is not an Excel emulator.

Capability Excel Standalone Univer demo
Source persistence Workbook Custom XML Page-session source
bf.inputs() Reactive workbook changes Reactive workbook changes
BF.OUTPUT() Streaming Excel custom function Univer wrapper
BF.FUNCTION() Streaming Excel custom function One-shot async wrapper
Consumer references Streaming formula anchor addresses Indexed formula cells
Shared-runtime cold start Excel shared runtime Browser page lifecycle
Notebook AI Eligible Office work/school identity Disabled

Use the browser demo to explore notebooks, but validate save/reopen and worksheet-function startup in the Excel add-in before distributing a workbook.

Public API versus implementation details

Notebook authors should depend on the documented public surface:

bf.ref(...)
bf.inputs(...)
bf.publish(...)

and the worksheet functions:

=BF.OUTPUT("name")
=BF.FUNCTION("name", ...)

Session IDs, nonces, message ports, protocol messages, Custom XML layout, shared-runtime stores, and driver internals are implementation details. Keeping those layers private lets Boardflare change the transport without forcing workbook authors to rewrite notebook code.

For trust boundaries, AI data flow, iframe connection validation, package/network behavior, and executable-workbook guidance, continue to Security and Data Flow.