Appendix A2 — Publishing Notebooks with Marimushka
Marimushka is a tool that exports marimo notebooks to static HTML and WebAssembly, then publishes them as a browsable site — no Python installation required for readers. It is the publishing layer for the marimo bundle in Rhiza.
What marimo notebooks are
Marimo notebooks are pure Python files (.py) that behave like reactive notebooks: change a value and everything that depends on it re-executes automatically. Unlike Jupyter notebooks, they are stored as plain Python, diff cleanly in git, and can be run as scripts or deployed as interactive web apps.
The marimo bundle in Rhiza brings marimo into your project:
# .rhiza/template.yml
templates:
- core
- github
- tests
- marimo # <-- adds marimo support
After syncing, your project gains a CI workflow that uses marimushka to export and publish all notebooks on every push.
Two kinds of output
Marimushka distinguishes two directories and exports them differently:
| Directory | Export mode | What the reader sees |
|---|---|---|
notebooks/ |
Edit mode (HTML) | Full notebook with visible code, editable in the browser |
apps/ |
Run mode (WebAssembly) | App UI only — code is hidden, runs entirely in the browser |
Put exploratory or tutorial notebooks in notebooks/. Put polished interactive tools in apps/. Both land on the same published site with an auto-generated index page.
Running marimushka locally
uvx marimushka export
By default this reads notebooks/ and apps/ from the current directory and writes output to _site/. Key options:
uvx marimushka export --notebooks notebooks/ --apps apps/ --output _site/
Open _site/index.html in a browser to preview the published site before pushing.
Configuration file
Persistent options live in .marimushka.toml at the project root:
notebooks = "notebooks"
apps = "apps"
output = "_site"
You can also tune parallelism, timeouts, and sandbox behaviour here. Once this file exists, uvx marimushka export picks it up automatically — no flags needed.
The GitHub Action
The marimo bundle includes a workflow that uses the jebel-quant/marimushka GitHub Action to export notebooks and deploy them to GitHub Pages on every push to main:
- name: Export notebooks
uses: jebel-quant/marimushka@v0.2.1
with:
notebooks: notebooks
apps: apps
The action produces a GitHub Pages artifact that a subsequent deploy job picks up — the same artifact-upload pattern used throughout the Rhiza CI stack.
Enabling GitHub Pages: Go to Settings → Pages → Source: GitHub Actions in your project repo. You only need to do this once.
Sandbox mode
By default, marimushka exports notebooks with --sandbox, which means each notebook runs in an isolated environment with its own dependencies declared in the notebook itself. This is the recommended approach: it keeps published notebooks reproducible and avoids environment bleed between notebooks.
If a notebook needs access to your project's installed packages, pass --no-sandbox. In that case, ensure uv sync has run before calling marimushka export, because the notebook will import from the project virtualenv.
Worked example
A project with this layout:
my-project/
├── notebooks/
│ ├── exploratory_analysis.py # marimo notebook
│ └── tutorial.py # marimo notebook
├── apps/
│ └── dashboard.py # marimo app
├── .marimushka.toml
└── ...
After uvx marimushka export, the _site/ directory contains:
_site/
├── index.html # auto-generated listing
├── notebooks/
│ ├── exploratory_analysis.html
│ └── tutorial.html
└── apps/
└── dashboard/
└── index.html # WebAssembly app
The published index page links to all of them. Readers can open notebooks in edit mode and run them interactively in the browser without installing anything.
Back to: Lesson 9 — Customising Safely | README