Maintaining the static notebooks
Run commands from the repository root using the locked environment:
uv sync
uv run python scripts/export_notebooks.py
The updater executes every new or changed guide in notebooks/ and every course
notebook in courses/. It writes saved outputs and source code under notebooks_html/,
adds source-specific links for browser editing, molab and marimo.app, and
refreshes the static catalog at notebooks_html/index.html. Reading links to other guides point to their local
HTML pages. Explicit interactive launch links and external references are kept.
Update one notebook:
uv run python scripts/export_notebooks.py notebooks/reference_frame.py
Check freshness without executing notebooks or writing files:
uv run python scripts/export_notebooks.py --check
A stale or missing export makes this command exit with a nonzero status. The
manifest records source, shared-input and HTML hashes, so an edited or removed
HTML file is also detected. Notebook edits rebuild the affected page. Changes
to data, helpers, images, pyproject.toml, uv.lock, the exporter, Python or
marimo invalidate the selected exports. Run the command without notebook paths
after a shared-input change to refresh the entire collection.
Force a fresh execution, for example after an external dataset changes:
uv run python scripts/export_notebooks.py --force
uv run python scripts/export_notebooks.py notebooks/reference_frame.py --force
Remote data changes cannot be detected by local hashes. Unseeded random examples
may also produce different results when re-executed. The default is four parallel
processes with a 300-second limit per notebook; --jobs 2 and --timeout 600
adjust these settings. A failed or timed-out export leaves the previous HTML
intact, records the failure, and returns a nonzero status. Fix the problem and
rerun the command before publishing.
Commit the changed notebook sources, generated HTML and notebooks_html/manifest.json
together. Publishing to master updates the repository’s existing GitHub Pages
site; the updater itself does not commit, push, or change hosting settings.
New notebook titles can be added to the README’s existing bullet list manually.
What the HTML contains
The updater uses marimo export html: these pages contain saved outputs rather
than a Python runtime. Expandable solutions work, while controls that require
Python cannot recompute results. The Edit in browser, Open in molab and Open in marimo.app links
open the same notebook in interactive mode. Download .py saves the exact Python
source included with the static page, including when opened locally. The header
also offers Download helper for notebooks that import notebook_resources.
It saves the exact shared notebook_resources.py; place it beside a downloaded
notebook and rerun the import cell if the notebook reports a missing helper.
The helper’s error message includes a direct source URL as another way to obtain
the file. The header
centers all navigation links and uses the notebook’s active theme colors and text font. Reading the static pages needs neither execution service;
the marimo display assets from a CDN and linked external media still need an
Internet connection. These saved pages are distinct from the editable WASM exports below.
The export process selects marimo’s headless Matplotlib backend so plt.show()
outputs are captured. A plot that is only created, or an accordion followed by
another expression, can still disappear. Finish such a cell with the intended
Figure/Axes or accordion object, as in the body-segment example. Review changed
plots and expandable answers after exporting; an execution-success status alone
does not prove that every intended display is visible.
Shared repository resources
functions/notebook_resources.py supplies repo_file through an ordinary Python
import. [tool.marimo.runtime] in pyproject.toml adds functions to marimo’s
module search path. Keep the implementation in that file; do not synchronize
copies into notebooks. Its local lookup and cached remote downloads also work
when the helper is saved beside a notebook opened outside the repository.
The native directory WASM exporter bundles the imported module into a wheel.
Preserve public/wheels alongside the frontend assets when publishing the
editable export. Changing the shared helper invalidates the saved snapshots;
run the exporter without notebook arguments to refresh the collection.
Expandable content
Use /// details for fixed written answers and explanations, keeping Markdown
and LaTeX together:
mo.md(r"""
/// details | Solution
The spring force is $F=kx$.
///
""")
Use mo.accordion when the content is assembled in Python, such as a computed
answer, generated table, plot, or widget:
mo.accordion(
{"Results": mo.vstack([mo.md("Computed force:"), mo.as_html(figure)])},
expanded=False,
)
Both forms should start collapsed for solutions. Keep their contents eagerly
rendered so the saved page contains the complete answer without a Python
backend. Avoid raw HTML <details> wrappers around Markdown or LaTeX. The
repository-wide rules are in AGENTS.md.
Editable GitHub Pages and automatic publication
All 88 notebooks are exported in editable mode. The configuration
scripts/notebooks.json contains {"include": "all"}, so new marimo notebooks added under
notebooks/ or courses/ are discovered automatically. Every README guide title opens
its saved HTML page; the page header offers browser editing, molab and marimo.app.
.github/workflows/pages.yml runs on every push to master and supports manual
runs from the Actions tab. It installs the locked environment, refreshes saved
outputs, builds the existing Cayman site with Jekyll, then adds editable pages
using marimo export html-wasm --mode edit directly at the published site root
(/BMC/<name>.html). The workflow first restores runner
ownership of Jekyll’s container-created output so the Python exporter can write
its additional files. The complete site is uploaded and
deployed only after successful build steps. Generated editor assets live in the
Pages artifact, not Git. The exporter stages all native exports before merging
them into the site, preserving the Cayman home page, theme assets, course material
and saved pages. A notebook named notebooks/index.py is rejected because
index.html is reserved for the home page. Pages must use GitHub Actions as
its publishing source.
To build/test the editable part locally without installing Jekyll:
uv run python scripts/export_notebooks.py
uv run python -c "import shutil; shutil.copytree('notebooks_html', '_site/notebooks_html', dirs_exist_ok=True)"
uv run python scripts/export_editable.py --site _site
uv run python -m http.server --directory _site 8000
Open http://localhost:8000/body_segment_parameters.html.
This local shortcut contains the notebook pages; the workflow also renders the
full Cayman homepage. If no home page exists, the exporter creates a simple
catalog for local use and refreshes that generated catalog on later builds.
An existing Cayman or custom home page is preserved. The native WASM export
includes its frontend assets, so
serve the whole _site/ folder over HTTP. The Python runtime, packages and
notebook data are downloaded in the browser; a first run can take longer.
No notebook needs to import the browser runtime.
Click Run all after opening the editor. Changes run locally in the browser
and do not update GitHub. Download the Python file to keep a modified copy.
The editor and saved pages have direct links to switch between modes. Older
published /html/, /notebooks_read/ and /nbs_read/ paths redirect to notebooks_html/;
/notebooks_edit/ and /nbs/ redirect to editors at the site root. Redirects
preserve query strings and section anchors. The nbs/ directory is no longer
present in the source repository; only compatibility redirects use that path
in the deployment. A failed native notebook export preserves previous local
editor files and prevents a workflow deployment.
Links between rendered guides resolve to their editable Pages versions, including
links added when an answer panel opens. Original Python source and external source
references are retained. The home page at /BMC/ links to the saved guides;
the saved catalog is at /BMC/notebooks_html/. Rebuilding an existing local site removes
retired editor HTML recorded in the previous export manifest, leaving unrelated
pages intact.