marimo-book 0.1.0a1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. marimo_book-0.1.0a1/.github/workflows/ci.yml +92 -0
  2. marimo_book-0.1.0a1/.github/workflows/docs.yml +50 -0
  3. marimo_book-0.1.0a1/.github/workflows/publish.yml +53 -0
  4. marimo_book-0.1.0a1/.gitignore +48 -0
  5. marimo_book-0.1.0a1/CHANGELOG.md +87 -0
  6. marimo_book-0.1.0a1/LICENSE +21 -0
  7. marimo_book-0.1.0a1/PKG-INFO +281 -0
  8. marimo_book-0.1.0a1/PUBLISHING.md +135 -0
  9. marimo_book-0.1.0a1/README.md +237 -0
  10. marimo_book-0.1.0a1/docs/book.yml +55 -0
  11. marimo_book-0.1.0a1/docs/content/authoring.md +133 -0
  12. marimo_book-0.1.0a1/docs/content/book_yml.md +174 -0
  13. marimo_book-0.1.0a1/docs/content/dependencies.md +108 -0
  14. marimo_book-0.1.0a1/docs/content/deploying.md +78 -0
  15. marimo_book-0.1.0a1/docs/content/example.py +95 -0
  16. marimo_book-0.1.0a1/docs/content/index.md +77 -0
  17. marimo_book-0.1.0a1/docs/content/inspiration.md +103 -0
  18. marimo_book-0.1.0a1/docs/content/link_checks.md +81 -0
  19. marimo_book-0.1.0a1/docs/content/quickstart.md +77 -0
  20. marimo_book-0.1.0a1/docs/content/roadmap.md +145 -0
  21. marimo_book-0.1.0a1/docs/content/widgets.md +104 -0
  22. marimo_book-0.1.0a1/pyproject.toml +99 -0
  23. marimo_book-0.1.0a1/src/marimo_book/__init__.py +3 -0
  24. marimo_book-0.1.0a1/src/marimo_book/assets/extra.css +66 -0
  25. marimo_book-0.1.0a1/src/marimo_book/assets/marimo_book.js +131 -0
  26. marimo_book-0.1.0a1/src/marimo_book/assets/mathjax.js +19 -0
  27. marimo_book-0.1.0a1/src/marimo_book/assets/scaffold/.github/workflows/deploy.yml +51 -0
  28. marimo_book-0.1.0a1/src/marimo_book/assets/scaffold/.gitignore +20 -0
  29. marimo_book-0.1.0a1/src/marimo_book/assets/scaffold/README.md +28 -0
  30. marimo_book-0.1.0a1/src/marimo_book/assets/scaffold/book.yml +47 -0
  31. marimo_book-0.1.0a1/src/marimo_book/assets/scaffold/content/example.py +54 -0
  32. marimo_book-0.1.0a1/src/marimo_book/assets/scaffold/content/intro.md +32 -0
  33. marimo_book-0.1.0a1/src/marimo_book/cli.py +382 -0
  34. marimo_book-0.1.0a1/src/marimo_book/config.py +276 -0
  35. marimo_book-0.1.0a1/src/marimo_book/launch_buttons.py +121 -0
  36. marimo_book-0.1.0a1/src/marimo_book/preprocessor.py +268 -0
  37. marimo_book-0.1.0a1/src/marimo_book/shell.py +241 -0
  38. marimo_book-0.1.0a1/src/marimo_book/transforms/__init__.py +7 -0
  39. marimo_book-0.1.0a1/src/marimo_book/transforms/anywidgets.py +257 -0
  40. marimo_book-0.1.0a1/src/marimo_book/transforms/callouts.py +106 -0
  41. marimo_book-0.1.0a1/src/marimo_book/transforms/link_rewrites.py +96 -0
  42. marimo_book-0.1.0a1/src/marimo_book/transforms/marimo_export.py +327 -0
  43. marimo_book-0.1.0a1/src/marimo_book/transforms/md_roles.py +78 -0
  44. marimo_book-0.1.0a1/src/marimo_book/watcher.py +235 -0
  45. marimo_book-0.1.0a1/tests/__init__.py +0 -0
  46. marimo_book-0.1.0a1/tests/fixtures/simple_notebook.py +43 -0
  47. marimo_book-0.1.0a1/tests/phase0_spike/README.md +36 -0
  48. marimo_book-0.1.0a1/tests/phase0_spike/RESULTS.md +51 -0
  49. marimo_book-0.1.0a1/tests/phase0_spike/SYNTAX_INVENTORY.md +69 -0
  50. marimo_book-0.1.0a1/tests/phase0_spike/docs/index.md +23 -0
  51. marimo_book-0.1.0a1/tests/phase0_spike/docs/javascripts/mathjax.js +19 -0
  52. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page01.md +7 -0
  53. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page02.md +7 -0
  54. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page03.md +7 -0
  55. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page04.md +7 -0
  56. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page05.md +7 -0
  57. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page06.md +7 -0
  58. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page07.md +7 -0
  59. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page08.md +7 -0
  60. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page09.md +7 -0
  61. marimo_book-0.1.0a1/tests/phase0_spike/docs/many/page10.md +7 -0
  62. marimo_book-0.1.0a1/tests/phase0_spike/docs/plotly.md +30 -0
  63. marimo_book-0.1.0a1/tests/phase0_spike/docs/prose.md +66 -0
  64. marimo_book-0.1.0a1/tests/phase0_spike/docs/stylesheets/extra.css +20 -0
  65. marimo_book-0.1.0a1/tests/phase0_spike/docs/widget.md +42 -0
  66. marimo_book-0.1.0a1/tests/phase0_spike/mkdocs.yml +90 -0
  67. marimo_book-0.1.0a1/tests/test_cli_commands.py +113 -0
  68. marimo_book-0.1.0a1/tests/test_config.py +91 -0
  69. marimo_book-0.1.0a1/tests/test_dependencies.py +91 -0
  70. marimo_book-0.1.0a1/tests/test_link_rewrites.py +85 -0
  71. marimo_book-0.1.0a1/tests/test_transforms.py +143 -0
  72. marimo_book-0.1.0a1/tests/test_watcher.py +202 -0
@@ -0,0 +1,92 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ test:
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ python-version: ["3.11", "3.12", "3.13"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - name: Set up Python ${{ matrix.python-version }}
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+ - name: Install
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install -e '.[dev]'
30
+ - name: Lint
31
+ run: ruff check src/ tests/
32
+ - name: Format check
33
+ run: ruff format --check src/ tests/
34
+ - name: Test
35
+ run: pytest -q
36
+
37
+ build:
38
+ runs-on: ubuntu-latest
39
+ needs: test
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+ - name: Set up Python
43
+ uses: actions/setup-python@v5
44
+ with:
45
+ python-version: "3.13"
46
+ - name: Install build backend
47
+ run: python -m pip install build
48
+ - name: Build sdist + wheel
49
+ run: python -m build
50
+ - name: Verify wheel contents
51
+ run: |
52
+ python -c "
53
+ import zipfile, pathlib
54
+ wheel = next(pathlib.Path('dist').glob('marimo_book-*.whl'))
55
+ with zipfile.ZipFile(wheel) as z:
56
+ names = z.namelist()
57
+ required = [
58
+ 'marimo_book/cli.py',
59
+ 'marimo_book/preprocessor.py',
60
+ 'marimo_book/assets/marimo_book.js',
61
+ 'marimo_book/assets/scaffold/book.yml',
62
+ 'marimo_book/assets/scaffold/.gitignore',
63
+ 'marimo_book/assets/scaffold/.github/workflows/deploy.yml',
64
+ ]
65
+ missing = [f for f in required if f not in names]
66
+ if missing:
67
+ raise SystemExit(f'wheel missing files: {missing}')
68
+ print(f'wheel OK ({len(names)} entries)')
69
+ "
70
+ - uses: actions/upload-artifact@v4
71
+ with:
72
+ name: dist-${{ github.sha }}
73
+ path: dist/
74
+ retention-days: 7
75
+
76
+ docs:
77
+ # Validates that the self-hosted docs book still builds — catches
78
+ # regressions before they land on main. The real deploy happens in
79
+ # docs.yml on push to main.
80
+ runs-on: ubuntu-latest
81
+ needs: test
82
+ steps:
83
+ - uses: actions/checkout@v4
84
+ - uses: actions/setup-python@v5
85
+ with:
86
+ python-version: "3.13"
87
+ - name: Install marimo-book with linkcheck extra
88
+ run: |
89
+ python -m pip install --upgrade pip
90
+ pip install -e '.[linkcheck]'
91
+ - name: Build docs --strict
92
+ run: marimo-book build -b docs/book.yml --strict
@@ -0,0 +1,50 @@
1
+ name: Build and deploy docs
2
+
3
+ # Self-host marimo-book's own docs (built with marimo-book) on GitHub
4
+ # Pages. Triggered on pushes to main that touch the docs tree or the
5
+ # package source (so tool changes also re-render the docs immediately).
6
+
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ paths:
11
+ - "docs/**"
12
+ - "src/**"
13
+ - "pyproject.toml"
14
+ - ".github/workflows/docs.yml"
15
+ workflow_dispatch:
16
+
17
+ permissions:
18
+ contents: read
19
+ pages: write
20
+ id-token: write
21
+
22
+ concurrency:
23
+ group: docs-pages
24
+ cancel-in-progress: true
25
+
26
+ jobs:
27
+ build:
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.13"
34
+ - name: Install marimo-book (editable)
35
+ run: pip install -e '.[linkcheck]'
36
+ - name: Build docs
37
+ run: marimo-book build -b docs/book.yml --strict
38
+ - uses: actions/upload-pages-artifact@v3
39
+ with:
40
+ path: docs/_site
41
+
42
+ deploy:
43
+ needs: build
44
+ runs-on: ubuntu-latest
45
+ environment:
46
+ name: github-pages
47
+ url: ${{ steps.deployment.outputs.page_url }}
48
+ steps:
49
+ - id: deployment
50
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,53 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes on any tag matching v*.
4
+ # Uses PyPI's Trusted Publisher setup (OIDC — no API token needed) — you
5
+ # must first register this repo + workflow on PyPI:
6
+ # https://docs.pypi.org/trusted-publishers/
7
+ #
8
+ # Project name on PyPI: marimo-book
9
+ # Owner / repo: ljchang/marimo-book
10
+ # Workflow name: publish.yml
11
+ # Environment name: pypi-publish
12
+
13
+ on:
14
+ push:
15
+ tags: ["v*"]
16
+ workflow_dispatch:
17
+
18
+ permissions:
19
+ contents: read
20
+ id-token: write # required for PyPI Trusted Publisher
21
+
22
+ jobs:
23
+ build:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - name: Set up Python
28
+ uses: actions/setup-python@v5
29
+ with:
30
+ python-version: "3.13"
31
+ - name: Build sdist + wheel
32
+ run: |
33
+ python -m pip install build
34
+ python -m build
35
+ - uses: actions/upload-artifact@v4
36
+ with:
37
+ name: dist
38
+ path: dist/
39
+
40
+ publish:
41
+ needs: build
42
+ runs-on: ubuntu-latest
43
+ environment:
44
+ name: pypi-publish
45
+ url: https://pypi.org/p/marimo-book
46
+ steps:
47
+ - uses: actions/download-artifact@v4
48
+ with:
49
+ name: dist
50
+ path: dist/
51
+ - uses: pypa/gh-action-pypi-publish@release/v1
52
+ # No `with:` block needed — trusted publishing pulls creds from
53
+ # PyPI's OIDC handshake with GitHub.
@@ -0,0 +1,48 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ .eggs/
11
+ wheels/
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ env/
17
+ .env
18
+
19
+ # Testing / coverage
20
+ .pytest_cache/
21
+ .coverage
22
+ .coverage.*
23
+ htmlcov/
24
+ .tox/
25
+ .nox/
26
+
27
+ # Type checkers
28
+ .mypy_cache/
29
+ .pyre/
30
+ .pytype/
31
+ .ruff_cache/
32
+
33
+ # marimo-book build artifacts
34
+ _site/
35
+ _site_src/
36
+ .marimo_book_cache/
37
+
38
+ # Editors
39
+ .vscode/
40
+ .idea/
41
+ *.swp
42
+ *.swo
43
+ .DS_Store
44
+
45
+ # uv
46
+ uv.lock
47
+ .python-version
48
+ __marimo__/
@@ -0,0 +1,87 @@
1
+ # Changelog
2
+
3
+ All notable changes to `marimo-book` will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0a1] — 2026-04-24
9
+
10
+ First alpha release. Usable end-to-end for single-book sites.
11
+
12
+ ### Added
13
+
14
+ **CLI** (`marimo-book ...`)
15
+
16
+ - `new <dir>` — scaffold a new book (book.yml, content/, .gitignore,
17
+ .github/workflows/deploy.yml, README). `--force` to write into
18
+ non-empty directories.
19
+ - `build` — preprocess + emit static site to `_site/`. `--strict` fails
20
+ on warnings; `--clean` blows away prior build artifacts first.
21
+ - `serve` — dev server with live reload. Runs an initial build, spawns
22
+ `mkdocs serve`, and a watchdog observer rebuilds on changes to
23
+ `content/` or `book.yml`.
24
+ - `check` — validate `book.yml` + referenced files without building.
25
+ - `clean` — remove `_site/`, `_site_src/`, `.marimo_book_cache/`.
26
+
27
+ **Config** (`book.yml`)
28
+
29
+ - Pydantic v2 schema with readable errors for unknown keys.
30
+ - Discriminated-union TOC (`file:` / `url:` / `section:` + `children:`).
31
+ - Author metadata, branding (logo, favicon, palette, fonts), launch
32
+ buttons, bibliography paths, analytics (Plausible / Google), per-page
33
+ render defaults, per-widget-class default state.
34
+ - Top-level `shell:` reserved for future `zensical` / `jinja` targets.
35
+
36
+ **Preprocessor transforms**
37
+
38
+ - `marimo_export` — `.py` → Markdown + inline HTML via
39
+ `marimo export ipynb --include-outputs`. Handles hide_code, mime bundles
40
+ (text/html, text/markdown, image/png|jpeg|svg+xml, text/plain,
41
+ streams, errors), and first-setup-cell elision.
42
+ - `callouts` — `<marimo-callout-output>` → Material admonition with the
43
+ kind mapped (info/note/success/tip/warning/danger/failure/neutral).
44
+ - `anywidgets` — `<marimo-anywidget>` → `<div class="marimo-book-anywidget">`
45
+ mount; AST-walks cell source to extract literal widget kwargs; merges
46
+ with `book.yml` `widget_defaults`. Strips
47
+ `<marimo-ui-element>` / `<marimo-slider>` / etc. wrappers around
48
+ kernel-dependent controls that have no static analog.
49
+ - `md_roles` — `{download}\`label <path>\`` → `[label](path)`;
50
+ `:::{glossary}` fence stripping.
51
+ - `link_rewrites` — `.ipynb` cross-refs → `.md` (when target exists);
52
+ `../images/` → `images/` in both Markdown links and HTML attrs.
53
+
54
+ **Shell generator**
55
+
56
+ - `book.yml` → `mkdocs.yml` with Material theme, standard pymdownx
57
+ extensions (arithmatex, admonition, blocks, details, highlight,
58
+ superfences, tabbed, tasklist), sensible nav feature flags, and an
59
+ `extra.css` derived from the book's palette.
60
+
61
+ **Runtime shim** (`assets/marimo_book.js`)
62
+
63
+ - Minimal anywidget-compatible model loader. At page load, finds every
64
+ `.marimo-book-anywidget` mount, decodes the inlined ES module from
65
+ `data-js-url`, and calls `module.default.render({model, el})` with a
66
+ seeded model. Works with Material's instant-navigation via
67
+ `document$.subscribe`.
68
+
69
+ ### Verified
70
+
71
+ - Full test suite: 46 passing across config, transforms, CLI, and watcher.
72
+ - End-to-end dartbrains build (34 TOC entries, 20 marimo notebooks):
73
+ 0 preprocessor errors, 2 cosmetic mkdocs warnings (both broken-link
74
+ issues in dartbrains source content, not tool bugs).
75
+ - Widget-heavy chapter (MR_Physics.py, 9 anywidgets) renders and animates
76
+ in a browser without marimo's frontend runtime.
77
+
78
+ ### Known limitations
79
+
80
+ - No WASM / hybrid render modes yet (static only).
81
+ - No dependency-graph-aware incremental cache; every rebuild is a full
82
+ rebuild.
83
+ - MyST cross-refs with `{ref}`, `{numref}`, `{eq}`, `{cite}`, etc. are
84
+ stripped through unchanged (no usage in any book we've migrated yet).
85
+ - Material for MkDocs is entering maintenance mode in ~12 months;
86
+ `marimo-book` is explicitly designed to port to [zensical](https://zensical.org)
87
+ when it stabilises (same `mkdocs.yml`, different build command).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luke Chang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,281 @@
1
+ Metadata-Version: 2.4
2
+ Name: marimo-book
3
+ Version: 0.1.0a1
4
+ Summary: Build clean, searchable static books from marimo notebooks and markdown
5
+ Project-URL: Homepage, https://github.com/ljchang/marimo-book
6
+ Project-URL: Repository, https://github.com/ljchang/marimo-book
7
+ Project-URL: Issues, https://github.com/ljchang/marimo-book/issues
8
+ Author-email: Luke Chang <luke.j.chang@dartmouth.edu>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: book,documentation,marimo,mkdocs,notebook,static-site
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Education
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Documentation
21
+ Classifier: Topic :: Software Development :: Documentation
22
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: beautifulsoup4>=4.12
25
+ Requires-Dist: jinja2>=3.1
26
+ Requires-Dist: lxml>=5.0
27
+ Requires-Dist: marimo<0.24,>=0.23
28
+ Requires-Dist: mkdocs-material>=9.5
29
+ Requires-Dist: mkdocs>=1.6
30
+ Requires-Dist: nbformat>=5.0
31
+ Requires-Dist: pybtex>=0.24
32
+ Requires-Dist: pydantic>=2.6
33
+ Requires-Dist: pymdown-extensions>=10.7
34
+ Requires-Dist: pyyaml>=6.0
35
+ Requires-Dist: typer>=0.12
36
+ Requires-Dist: watchdog>=4.0
37
+ Provides-Extra: dev
38
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
39
+ Requires-Dist: pytest>=8.0; extra == 'dev'
40
+ Requires-Dist: ruff>=0.4; extra == 'dev'
41
+ Provides-Extra: linkcheck
42
+ Requires-Dist: mkdocs-htmlproofer-plugin>=1.3; extra == 'linkcheck'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # marimo-book
46
+
47
+ Build clean, searchable static books from [marimo](https://marimo.io)
48
+ notebooks and Markdown files.
49
+
50
+ `marimo-book` is a Jupyter-Book-style static site generator built
51
+ specifically for marimo `.py` notebooks. It produces polished multi-page
52
+ sites with:
53
+
54
+ - **Collapsible sidebar** and chapter-aware navigation
55
+ - **Fast full-text search** across prose *and* baked cell outputs
56
+ - **Admonitions, math, figures, tables** with Material for MkDocs defaults
57
+ - **Anywidgets that render statically** (no marimo kernel required)
58
+ - **Launch buttons** per-chapter for molab / GitHub / download `.py`
59
+ - **Dark-mode toggle** that persists across navigation
60
+ - **GitHub Pages deploy workflow** scaffolded in for you
61
+
62
+ ## Status
63
+
64
+ **Alpha** (v0.1.0a1, April 2026). `marimo-book` is usable end-to-end and is
65
+ actively building a real course site ([dartbrains](https://github.com/ljchang/dartbrains)),
66
+ but the `book.yml` schema may still change before v1.0. Pin the exact version
67
+ in your project until we signal stability.
68
+
69
+ ## Install
70
+
71
+ ```bash
72
+ pip install marimo-book
73
+ ```
74
+
75
+ Requires Python 3.11+.
76
+
77
+ ## Quickstart
78
+
79
+ ```bash
80
+ # Scaffold a new book
81
+ marimo-book new mybook
82
+ cd mybook
83
+
84
+ # Live-reload dev server (http://127.0.0.1:8000/)
85
+ marimo-book serve
86
+ #
87
+ # Note on macOS: mkdocs's browser auto-reload is flaky on some
88
+ # macOS setups. If the browser doesn't refresh automatically after a
89
+ # save, hard-refresh (Cmd-R). The preprocessor + rebuild are
90
+ # reliable; only the browser push is affected.
91
+
92
+ # One-shot static build (emits ./_site/)
93
+ marimo-book build
94
+
95
+ # Validate book.yml + content without building
96
+ marimo-book check
97
+
98
+ # Remove build artifacts
99
+ marimo-book clean
100
+ ```
101
+
102
+ Deploy to GitHub Pages by pushing the scaffolded workflow
103
+ (`.github/workflows/deploy.yml`) to `main` on a repo with Pages enabled.
104
+
105
+ ## How it works
106
+
107
+ Two-stage build, by design:
108
+
109
+ ```
110
+ content/*.md + *.py + book.yml
111
+ → marimo-book preprocessor
112
+ → _site_src/docs/*.md + _site_src/mkdocs.yml
113
+ → mkdocs build (Material theme)
114
+ → _site/
115
+ ```
116
+
117
+ 1. The preprocessor reads `book.yml` and walks the TOC. For each `.md` it
118
+ applies small content transforms (MyST `:::{glossary}` fence stripping,
119
+ `{download}` role rewrite, `../images/` path fixups, `.ipynb` →
120
+ `.md` cross-ref rewriting). For each marimo `.py` it runs
121
+ `marimo export ipynb --include-outputs` and converts the cells into
122
+ Markdown + inline HTML, translating marimo custom elements
123
+ (`<marimo-callout-output>`, `<marimo-anywidget>`) into their static
124
+ analogs.
125
+ 2. Material for MkDocs (or later, zensical — which reuses `mkdocs.yml`
126
+ verbatim) builds the final HTML.
127
+
128
+ The preprocessor is **not** a mkdocs plugin — it emits plain Markdown +
129
+ inline HTML. This keeps the shell swappable: Material today, zensical
130
+ tomorrow, or a hand-rolled Jinja shell as a last-resort fallback.
131
+
132
+ ## `book.yml`
133
+
134
+ ```yaml
135
+ title: My Book
136
+ description: A static site from marimo notebooks + Markdown.
137
+ authors:
138
+ - name: Your Name
139
+ orcid: 0000-0000-0000-0000 # optional
140
+ repo: https://github.com/you/yourbook
141
+ branch: main
142
+
143
+ theme:
144
+ palette:
145
+ primary: "#1976D2"
146
+ accent: "#FF9800"
147
+
148
+ launch_buttons:
149
+ molab: true # "Open in molab" button on every .py page
150
+ github: true # "View on GitHub"
151
+ download: true # "Download .py source"
152
+
153
+ # Per-widget default state for anywidgets whose JS needs initial model
154
+ # values to render on first paint. Literal kwargs from the cell override
155
+ # these; unset keys fall through to the widget's own JS defaults.
156
+ widget_defaults:
157
+ CompassWidget:
158
+ b0: 3.0
159
+
160
+ toc:
161
+ - file: content/intro.md
162
+ - section: Part I
163
+ children:
164
+ - file: content/chapter1.py
165
+ - file: content/chapter2.py
166
+ - section: Part II
167
+ children:
168
+ - file: content/chapter3.py
169
+ - url: https://example.org/external-reading
170
+ title: External Reading
171
+ ```
172
+
173
+ See `marimo-book new` for a full starter template with comments on every
174
+ field.
175
+
176
+ ## What's supported in v0.1
177
+
178
+ **Material for MkDocs handles natively (free):**
179
+
180
+ - Full-text search, dark mode, keyboard shortcuts, code-copy buttons,
181
+ collapsible sidebar, breadcrumbs, next/previous navigation,
182
+ admonitions (`!!! note` / `!!! tip` / `!!! warning` / etc.), math,
183
+ responsive theme, edit-this-page link, analytics, top-of-page banner
184
+
185
+ **Preprocessor adds:**
186
+
187
+ - `book.yml` → `mkdocs.yml` generation (TOC, theme, palette, fonts,
188
+ extensions, plugins all derived)
189
+ - `.py` → rendered Markdown + inlined anywidget / callout / image outputs
190
+ - Static rehydration of anywidgets via a small JS shim
191
+ (`marimo_book.js`, loaded via `extra_javascript`)
192
+ - Launch-button row per chapter (molab / GitHub / download)
193
+ - MyST `{download}\`label <path>\`` → `[label](path)`
194
+ - `:::{glossary}` fence stripping (definition lists pass through natively)
195
+ - `[text](Foo.ipynb)` → `[text](Foo.md)` cross-ref rewrite when `Foo.md`
196
+ exists in the staged tree
197
+ - `../images/` → `images/` relative-path fixup when `content/` is flattened
198
+ - First-code-cell hiding (the setup-imports convention) — opt out via
199
+ `defaults.hide_first_code_cell: false`
200
+
201
+ ## Notebook dependencies
202
+
203
+ Notebooks need their imports satisfied at build time (marimo re-executes
204
+ every cell to capture outputs). `marimo-book` supports two modes; pick
205
+ in `book.yml`:
206
+
207
+ ```yaml
208
+ dependencies:
209
+ mode: env # default — reuse the active venv
210
+ # mode: sandbox # per-notebook PEP 723 isolation via uv
211
+ ```
212
+
213
+ **`env` mode** (default). Whatever Python env runs `marimo-book` provides
214
+ the deps. The typical consumer has a `pyproject.toml` at the book root
215
+ listing notebook dependencies (`numpy`, `pandas`, your domain package,
216
+ etc.), installs with `pip install -e .` or `uv pip install -e .`, and
217
+ runs `marimo-book` from that env. Fast, straightforward, good when all
218
+ notebooks share the same stack.
219
+
220
+ **`sandbox` mode.** Passes `--sandbox` to `marimo export`. Each notebook
221
+ must declare its own deps via PEP 723 inline script metadata:
222
+
223
+ ```python
224
+ # /// script
225
+ # dependencies = [
226
+ # "marimo>=0.23",
227
+ # "numpy>=2.0",
228
+ # "pandas>=2.0",
229
+ # ]
230
+ # ///
231
+
232
+ import marimo
233
+ # ...
234
+ ```
235
+
236
+ At build time, marimo uses `uv run --isolated` to provision a fresh env
237
+ per notebook. ~5–10 s on first run, cached after. Notebooks become
238
+ portable — copy a `.py` into any repo with `uv` installed and it just
239
+ works. The book root doesn't need a `pyproject.toml`.
240
+
241
+ **Override per invocation:**
242
+
243
+ ```bash
244
+ marimo-book build --sandbox # force sandbox regardless of book.yml
245
+ marimo-book build --no-sandbox # force env mode
246
+ marimo-book serve --sandbox # slower iteration, but reproducible
247
+ ```
248
+
249
+ Use `env` for local dev loops and `sandbox` on CI where reproducibility
250
+ matters more than rebuild speed.
251
+
252
+ ## Broken-link checking
253
+
254
+ `mkdocs build --strict` (use `marimo-book build --strict`) already fails on
255
+ broken **in-tree** links and anchors. For external URLs and image `src`
256
+ attributes, opt into the `htmlproofer` plugin:
257
+
258
+ ```yaml
259
+ # book.yml
260
+ check_external_links: true
261
+ ```
262
+
263
+ ```bash
264
+ pip install 'marimo-book[linkcheck]'
265
+ marimo-book build --strict
266
+ ```
267
+
268
+ External link checking hits the live web, so it's slow (~1–3 s per link).
269
+ Keep it off on CI unless you're cutting a release.
270
+
271
+ **Not in v0.1 (planned):**
272
+
273
+ - WASM / hybrid render modes — static only in v0.1; architecture already
274
+ supports the branch
275
+ - Dependency-graph-aware incremental build cache
276
+ - BibTeX citations with hover-cards (no book needs them yet)
277
+ - PDF / EPUB export — opt-in via `mkdocs-with-pdf` if needed
278
+
279
+ ## License
280
+
281
+ [MIT](LICENSE)