This repo deploys the marimo notebook suite as WebAssembly HTML exports.
The GitHub Actions workflow at .github/workflows/pages.yml runs on pushes to dev or main, and on manual dispatch.
It:
- installs dependencies with
uv - lints
src/,notebooks/, andscripts/ - validates each notebook with
marimo check - exports each notebook with
marimo export html-wasm - uploads the generated
site/directory as the GitHub Pages artifact
For a local rebuild and preview:
uv sync
uv run python scripts/build_pages.py
uv run python -m http.server --directory site 8010If port 8010 is already busy, use the next available port:
uv run python -m http.server --directory site 8011For GitHub Pages:
uv sync --frozen --extra dev
uv run ruff check src notebooks scripts
uv run python scripts/build_pages.py
git status --short
git add .github/workflows/pages.yml README.md docs notebooks scripts pyproject.toml uv.lock
git commit -m "Update marimo notebook suite"
git push origin mainThe push triggers the Deploy GitHub Pages workflow automatically when Pages is set to
GitHub Actions. Use the manual workflow button only for the first deployment or when you
want to rerun a deploy without a new commit.
In GitHub, set Pages to use GitHub Actions as the source:
Settings -> Pages -> Build and deployment -> Source -> GitHub Actions
The first deployment may need to be kicked manually:
Actions -> All workflows -> Deploy GitHub Pages -> Run workflow
After this, pushes to dev or main redeploy automatically.
GitHub Pages is static, so the app must not contain the private CoRE Stack API key. Users paste their API key into the app at runtime. The key stays in their browser session and is not committed or stored by this repo.
Because the exported app runs in the user's browser, the CoRE Stack API must allow browser requests from the GitHub Pages origin.
The public API currently responds to an OPTIONS preflight, but does not include Access-Control-Allow-Origin or Access-Control-Allow-Headers for X-API-Key. If that remains true in production, the GitHub Pages app will load but browser requests to the API will be blocked before they reach Django.
Fix this by allowing the deployed Pages origin, for example:
https://amit-spatial.github.io- the final custom docs/webapps origin, once chosen
The backend also needs to allow the X-API-Key request header for public API routes.
For the current Django backend, this means setting CORS_ALLOWED_ORIGINS in production to include the Pages origin. X-API-Key is already present in CORS_ALLOW_HEADERS in nrm_app/settings.py.
Add the above block to your settings.py (replace the existing else: branch for CORS_ALLOWED_ORIGINS).
- Redeploy your Django backend.
- Test from your GitHub Pages app:
- Open DevTools → Network tab.
- Make a request to your API.
- Verify the response headers include:
- Access-Control-Allow-Origin: https://amit-spatial.github.io
- Access-Control-Allow-Headers: X-API-Key
if DEBUG:
CORS_ALLOW_ALL_ORIGINS = True
else:
CORS_ALLOWED_ORIGINS = [
"https://amit-spatial.github.io", # GitHub Pages origin
# Add your custom domain once chosen, e.g.:
# "https://docs.core-stack.org",
]
CORS_ALLOWED_ORIGIN_REGEXES = [
r"^http://localhost:\d+$",
r"^http://127\.0\.0\.1:\d+$",
r"^http://192\.168\.\d{1,3}\.\d{1,3}(:\d+)?$",
]
CORS_ALLOW_HEADERS = list(default_headers) + [
"ngrok-skip-browser-warning",
"content-disposition",
"X-API-Key",
]uv run python scripts/build_pages.py
uv run python -m http.server --directory site 8010Use port 8010 by default for local previews. If it is already in use, choose the next
free port and keep the site/ directory the same.
The root site/index.html links to:
/public-data-browser//exploratory-layer-studio//mws-deep-dive//action-planner//guided-map-tour/
- Create a
.pymarimo notebook innotebooks/. - Keep it browser-safe for WebAssembly export: no private secrets, no local-only paths, no server-only imports.
- Add the notebook to
APPSinscripts/build_pages.py. - Run
uv run python scripts/build_pages.py. - Preview at
http://127.0.0.1:8010/. - Commit and push to
main.
The generated site/ directory is ignored and should not be committed.
The repo https://github.com/amit-spatial/marimo-gh-pages-template is a useful reference when this deployment needs to become more generic.
It demonstrates:
- exporting app files from
apps/in run mode - exporting notebook files from
notebooks/in edit mode - generating the root index through Jinja templates
- keeping notebook-local assets in
public/
This project currently keeps all deployable experiences as run-mode apps, so
scripts/build_pages.py is intentionally simpler. The template can still guide a future
split between public apps, editable notebooks, reusable templates, and static assets.
- GitHub Pages is static; API keys must be entered at runtime or loaded locally from
.env. - The deployed app still needs backend CORS for API calls from
https://amit-spatial.github.io. - The local server does not solve production CORS; it only previews the static export.
- If a notebook uses new packages, add them to both
pyproject.tomland the notebook PEP 723 block. - If the API shape changes, update notebook helper functions before redeploying.