@@ -7,134 +7,81 @@ Branch: lb/myst-migration
77## Context
88
99` scientific-python/scientific-python-myst-theme ` provides shared MyST styling,
10- config, plugins (` team-grid.mjs ` ), assets (logo, favicon, CSS), and footer
11- template for Scientific Python MyST sites. It is distributed as a ** copier
12- template** , not a pip or npm package. The intended consumption pattern is for
13- a site's ` myst.yml ` to ` extends: ` a ` config/scientific-python.yml ` file that
14- ships in the template.
15-
16- The theme is brand-new (created 2026-05-18, 0 tagged releases, 5 forks as of
17- 2026-05-19). The upstream HEAD on ` main ` is currently the only available
18- pinning target.
19-
20- This site already uses one git submodule (` external-content/cookie ` , Jekyll,
21- pinned to ` 2025.10.01 ` , see ADR 0004). We need a strategy for pulling theme
22- files into ` content/ ` that is reproducible on Netlify CI (` make html-all ` ),
23- on a fresh ` git clone ` + ` myst start ` , and across maintainer machines, while
24- allowing the theme to evolve upstream.
25-
26- Constraint: MyST resolves paths in ` myst.yml ` (including ` extends: ` , ` style: ` ,
27- ` logo: ` , plugins) relative to the ` myst.yml ` location, which is ` content/ ` .
28- Theme files must end up at predictable paths under ` content/ ` .
10+ config, plugins (` team-grid.mjs ` ), assets (logo, favicon, CSS), and a footer
11+ template. It is distributed as a ** copier template** , not a pip/npm package: the
12+ intended consumption pattern is for a site's ` myst.yml ` to ` extends: ` a
13+ ` config/scientific-python.yml ` shipped in the template.
14+
15+ The theme is brand-new (created 2026-05-18, 0 tagged releases), so upstream
16+ ` main ` HEAD is the only pinning target. We need a strategy for pulling theme
17+ files into ` content/ ` that is reproducible on Netlify CI (` make html-all ` ), on a
18+ fresh ` git clone ` + ` myst start ` , and across maintainer machines.
19+
20+ Constraint: MyST resolves ` myst.yml ` paths (` extends: ` , ` style: ` , ` logo: ` ,
21+ plugins) relative to the ` myst.yml ` location, which is ` content/ ` . Theme files
22+ must land at predictable paths under ` content/ ` .
2923
3024## Decision
3125
32- Adopt ** committed theme files, vendored selectively from a copier render**
33- (a refinement of Option 2).
26+ Adopt ** committed theme files, vendored selectively from a copier render** (a
27+ refinement of Option 2).
3428
35- The upstream template is a _ scaffold-a-new-site_ template: a full
36- ` copier copy ` renders ` index.md ` , ` myst.yml ` , ` about.md ` , ` news.md ` ,
37- ` Makefile ` , and ` .gitignore ` alongside the theme infrastructure. Our
38- ` content/ ` already holds a populated site, so a direct
39- ` copier copy ... content/ ` would clobber ` index.md ` /` myst.yml ` and add
40- unwanted pages. Therefore we render to a throwaway directory and copy in only
41- the theme-infrastructure files.
29+ Upstream is a _ scaffold-a-new-site_ template: a full ` copier copy ` renders
30+ ` index.md ` , ` myst.yml ` , ` about.md ` , ` news.md ` , ` Makefile ` , ` .gitignore `
31+ alongside the theme infrastructure. Our ` content/ ` already holds a populated
32+ site, so a direct copy would clobber ` index.md ` /` myst.yml ` and add unwanted
33+ pages. We therefore render to a throwaway dir and copy in only the theme files.
4234
4335Implementation (as performed):
4436
45- - Render once to a temp dir:
46- ` pixi exec --spec copier copier copy --trust --defaults gh:scientific-python/scientific-python-myst-theme <tmp> ` .
47- (` copier ` is run ephemerally via ` pixi exec ` ; it is not a project
48- dependency.)
49- - Vendor only these files into ` content/ ` , committed to the repo:
50- ` config/scientific-python.yml ` , ` assets/css/scientific-python.css ` ,
51- ` assets/images/logo.svg ` , ` assets/images/favicon.ico ` , ` team-grid.mjs ` ,
52- ` footer.md ` , and ` .copier-answers.yml ` (kept for provenance: it records
53- the upstream ` _commit ` ).
54- - Add ` extends: config/scientific-python.yml ` to ` content/myst.yml ` . The
55- extended config provides ` site.template ` , ` folders ` , and the ` hide_* `
56- options. ` site.options.style ` must be respecified locally because ` extends `
57- overrides (does not append) it: it is set to a list of the theme CSS plus a
58- local ` assets/css/custom.css ` override (the former top-level ` custom.css ` ,
59- relocated under ` content/assets/css/ ` ).
60- - The previously duplicated top-level ` assets/ ` (logo and favicon, byte
61- identical to the theme copies) is removed; ` content/assets/ ` is now the
62- single source.
63- - Do not add copier to the Netlify build command or to ` make prepare ` . CI
64- consumes the committed files as-is.
65-
66- Update path: because our ` index.md ` /` myst.yml ` have diverged from the
67- template, ` copier update ` cannot be run cleanly against ` content/ ` (it would
68- conflict on the scaffold files). Updates are instead done by re-rendering to a
69- temp dir and diffing the vendored files by hand. Revisit Option 3 (scheduled
70- GitHub Action) and a cleaner ` copier update ` flow once the upstream theme
71- separates "theme core" from "site scaffold" and cuts tagged releases.
37+ - Render once to a temp dir via `pixi exec --spec copier copier copy --trust
38+ --defaults gh: scientific-python /scientific-python-myst-theme <tmp >` (copier is
39+ run ephemerally; it is not a project dependency).
40+ - Vendor only these into ` content/ ` , committed: ` config/scientific-python.yml ` ,
41+ ` assets/css/scientific-python.css ` , ` assets/images/logo.svg ` ,
42+ ` assets/images/favicon.ico ` , ` team-grid.mjs ` , ` footer.md ` , and
43+ ` .copier-answers.yml ` (provenance: records upstream ` _commit ` ).
44+ - Add ` extends: config/scientific-python.yml ` to ` content/myst.yml ` . ` style `
45+ must be respecified locally — ` extends ` overrides (does not append) it — as a
46+ list of theme CSS plus a local ` assets/css/custom.css ` override.
47+ - Remove the previously duplicated top-level ` assets/ ` (logo/favicon byte
48+ identical to theme copies); ` content/assets/ ` is now the single source.
49+ - Do not add copier to the Netlify build or ` make prepare ` ; CI consumes the
50+ committed files as-is.
51+
52+ Update path: ` copier update ` cannot run cleanly (it conflicts on the diverged
53+ scaffold files), so updates are done by re-rendering to a temp dir and diffing
54+ the vendored files by hand. Revisit Option 3 once upstream separates "theme
55+ core" from "site scaffold" and cuts tagged releases.
7256
7357Known upstream gap: ` config/scientific-python.yml ` sets
74- ` site.parts.primary_sidebar_footer: sidebar-footer.md ` , but the template ships
75- no such file. The build emits a non-fatal warning
76- (` Part file does not exist: sidebar-footer.md ` ). Tracked to be raised with the
77- theme maintainer separately; not stubbed locally.
58+ ` primary_sidebar_footer: sidebar-footer.md ` , which the template does not ship; the
59+ build emits a non-fatal warning. To be raised upstream, not stubbed.
7860
79- ` external-content/cookie ` is unaffected and remains a git submodule per
80- ADR 0004. The two integrations differ in kind: cookie is a separately-built
81- Jekyll site whose output is overlaid on ` public/development/ ` ; the theme is
82- config plus static assets consumed by the MyST build itself.
61+ ` external-content/cookie ` is unaffected (ADR 0004): it is a separately-built
62+ Jekyll site overlaid on ` public/development/ ` , whereas the theme is config plus
63+ assets consumed by the MyST build itself.
8364
8465## Options considered
8566
86- 1 . ** Git submodule** (mirror cookie pattern) — add
87- ` external-content/scientific-python-myst-theme ` , have ` make prepare ` copy
88- files into ` content/ ` . Consistent with cookie, but introduces transient
89- copied files, dual source of truth (submodule + working copy), and forces
90- a copy step into every fresh ` myst start ` . Also: the theme is a copier
91- template, not a runnable artifact, so cloning the source repo as a
92- submodule is a structural mismatch.
93- 2 . ** Copier copy, committed files** — ` copier copy ` once, commit rendered
94- files, maintainers run ` copier update ` manually. Files in the repo,
95- zero new build-time deps, ` myst start ` works on fresh clone. Tradeoff:
96- manual update cadence; theme drift possible if maintainers neglect updates.
97- 3 . ** Scheduled GitHub Action + copier update** — cron-triggered workflow runs
98- ` copier update --defaults ` and opens a PR on diff. Automatic; files still
99- committed. Adds a workflow file and a maintenance surface (handling
100- merge conflicts in auto-PRs). Premature while upstream has no releases.
101- 4 . ** Pre-commit hook running copier update** — slows every commit, doesn't
102- help CI on a fresh checkout, and surprises contributors who don't have
103- copier installed. Rejected.
104- 5 . ** Rethink cookie integration** — cookie is a separately-built Jekyll site
105- with its own Ruby toolchain, release tags, and an independent contributor
106- community. Submodule + Makefile remains the right shape for it. The
107- theme decision does not alter ADR 0004.
67+ 1 . ** Git submodule** (mirror cookie) — introduces transient copied files, dual
68+ source of truth, and a copy step on every ` myst start ` ; a copier template is
69+ not a runnable artifact, so a source submodule is a structural mismatch.
70+ 2 . ** Copier copy, committed files** (chosen) — zero new build-time deps,
71+ ` myst start ` works on fresh clone. Tradeoff: manual update cadence, drift risk.
72+ 3 . ** Scheduled GitHub Action + copier update** — cron PR on diff; automatic but
73+ adds a workflow and auto-PR conflict maintenance. Premature with no releases.
74+ 4 . ** Pre-commit hook running copier update** — slows every commit, doesn't help
75+ CI on fresh checkout, surprises contributors without copier. Rejected.
76+ 5 . ** Rethink cookie integration** — cookie's Ruby toolchain and release tags keep
77+ submodule + Makefile right for it; this decision does not alter ADR 0004.
10878
10979## Consequences
11080
111- - ` content/config/scientific-python.yml ` ,
112- ` content/assets/css/scientific-python.css ` ,
113- ` content/assets/css/custom.css ` , ` content/assets/images/logo.svg ` ,
114- ` content/assets/images/favicon.ico ` , ` content/team-grid.mjs ` ,
115- ` content/footer.md ` , and ` content/.copier-answers.yml ` are committed to the
116- repo.
117- - ` content/myst.yml ` gains ` extends: config/scientific-python.yml ` , points
118- ` logo ` /` favicon ` at the content-local theme assets, and respecifies ` style `
119- as a list (theme CSS plus local ` custom.css ` ).
120- - The former top-level ` assets/ ` directory is removed: its ` logo.svg ` and
121- ` favicon.ico ` were byte identical to the theme copies, and its unused
122- ` custom.css ` Lato override was relocated to ` content/assets/css/custom.css `
123- and wired into ` myst.yml ` .
124- - Netlify config (` netlify.toml ` ) is unchanged. ` make prepare ` is unchanged.
125- ` make html-all ` continues to work because all theme files are already on
126- disk after ` git clone ` .
127- - Fresh clone developer experience: ` git clone && cd content && myst start `
128- works with no extra setup beyond mystmd itself.
129- - The committed build path is the ` Makefile ` (` make html ` / ` make html-all ` ,
130- used by Netlify), which already runs the build inside ` content/ ` . The
131- ` pixi.toml ` ` build ` /` serve ` tasks are a local-only convenience (` pixi.toml `
132- is in ` .git/info/exclude ` ); they were fixed to run with ` cwd = content ` so
133- they work from the repo root.
134- - Theme updates are manual (re-render and diff). Risk: drift from upstream.
135- Mitigation: revisit Option 3 once upstream separates theme core from site
136- scaffold and cuts a tagged release.
137- - The lack of upstream tags is recorded here; when the theme publishes its
138- first release, pin ` .copier-answers.yml ` to that tag.
139- - A non-fatal ` sidebar-footer.md ` warning remains pending an upstream fix.
140- - Cookie submodule strategy (ADR 0004) is unaffected.
81+ - ` netlify.toml ` and ` make prepare ` are unchanged; ` make html-all ` (the
82+ Netlify build path) works because all theme files are on disk after `git
83+ clone` . Fresh clone ` git clone && cd content && myst start` needs no setup.
84+ - ` pixi.toml ` ` build ` /` serve ` tasks (local-only, git-excluded) were fixed to run
85+ with ` cwd = content ` .
86+ - Manual updates risk upstream drift; pin ` .copier-answers.yml ` to the first
87+ tagged release when available, and revisit Option 3 then.
0 commit comments