Repository navigation
Launch control cannot be turned off and links to a nonexistent notebooks repo on sites without one #205
Description
Part of #147 (parity study 2026-09-11 — content correctness).
Revised in place 2026-09-11 after the maintainer review:
- Decided: the Launch control becomes opt-in and explicitly configured, with option names designed for more launch services.
- Deferred: whether and where the theme checks that a notebook exists before showing Launch. The options are documented below.
The revision is recorded in the comments.
Problem
The Launch control (in the desktop toolbar and the mobile overflow menu) appears on every page of any project that sets project.github. It opens Colab on a notebook repository whose name the theme guesses: the source repository, minus any .myst suffix, plus .notebooks. Only launch_repo_url or launch_repo_suffix override the guess, and no option hides the control. A site without a notebooks repository therefore links readers to Colab on a repository that does not exist. For example, lecture-wasm's /cobweb/ opens https://colab.research.google.com/github/QuantEcon/lecture-wasm.notebooks/blob/main/cobweb.ipynb, and that repository returns 404 (verified 2026-09-11).
The book theme never guesses. It shows Launch only when nb_repository_url is set (layout.html L418-L420, launch.py L40), and adds each service only when that service is configured: Colab needs launch_buttons.colab_url (launch.py L124-L129).
Where this theme does it:
- The notebook repository comes from
project.github, and the only early return is a missing repo or page location (LaunchButton.tsx L15-L31). - The name is always derived as source plus suffix, unless
launch_repo_urlis set (launchUrls.ts L30-L43). - Five
launch_*string options change the URL, and none turns the control off (template.yml L106-L123).
What the lecture repositories have (verified 2026-09-11)
| Group | Repositories | Notebooks repository | Sphinx site today | This theme today |
|---|---|---|---|---|
| Configured, and the repository exists | 13: lecture-python-intro, lecture-python-programming, lecture-python.myst, lecture-python-advanced.myst, lecture-jax, continuous_time_mcs, lecture-dle, lecture-eqm, lecture-stats, lecture-tools-techniques, lecture-julia.myst, lecture-datascience.myst | Exists, and matches nb_repository_url |
Launch works | Launch works (the guessed name happens to match) |
| Not configured | 5: lecture-wasm; lecture-python-programming.fa, .fr, .zh-cn, .ml | None | No Launch | Dead link (live on lecture-wasm) |
| Configured, but the repository is missing | 3: lecture-dp, lecture-python.zh-cn, lecture-intro.zh-cn | nb_repository_url points at a 404 |
Dead link on every page | Dead link |
The last row is fixed on the Sphinx side by QuantEcon/lecture-dp#60, QuantEcon/lecture-python.zh-cn#279 and QuantEcon/lecture-intro.zh-cn#305. Each removes the dead nb_repository_url, following QuantEcon/lecture-python-programming.fa#145.
Decision (2026-09-11)
-
Opt-in and explicit. Launch renders only when a notebook source is configured and at least one launch service is enabled. The theme stops guessing: the derivation from
project.github, the.mystrule andlaunch_repo_suffixall go. -
Flat option names now, shaped for nesting later. Theme options can only be
boolean,string,number,choiceorfile, in both the QuantEcon mystmd fork and upstream, so a nested block cannot be declared yet. Template options can only be scalars, so site templates pack lists and nested settings into YAML strings mystmd#112 asks for structured options. Each flat name is the future nested path with underscores, so the migration is mechanical:Option (flat, now) Nested, once mystmd supports it Replaces Sphinx equivalent launch_notebook_repolaunch.notebook.repolaunch_repo_urlnb_repository_urllaunch_notebook_branch(defaultmain)launch.notebook.branchlaunch_branchnb_branchlaunch_notebook_dirlaunch.notebook.dirlaunch_notebooks_pathnb_path_to_notebookslaunch_notebook_source_dirlaunch.notebook.source_dirlaunch_source_pathpath_to_docslaunch_colablaunch.colab(implicit today) launch_buttons.colab_urllaunch_notebook_url(future)launch.notebook.url— Update Colab badge URLs to support notebooks on gh-pages quantecon-book-theme#359 (notebooks served from the site) launch_binderhub_url,launch_jupyterhub_url(future)launch.binderhub_url,launch.jupyterhub_url— launch_buttons.binderhub_url,launch_buttons.jupyterhub_urllaunch_repo_suffixis removed. All names are snake_case, like every other theme option. -
Launch services are kept apart from the notebook source. The
launch_notebook_*group says where the notebook lives;launch_colaband the future service keys say what can open it. One source serves every service, so a service is not a property of the notebook. With more than one service enabled, the control becomes a menu, and that needs no config change. -
Migration. A lecture repository sets
launch_notebook_repoonly if that repository exists; the step is on the migration checklist (Lecture repos moving off the Sphinx theme have no checklist of what myst.yml and CI must now set #209).- lecture-wasm loses its dead link at its next theme bump, with no config change.
- lecture-python-programming's
jb2branch addslaunch_notebook_repoandlaunch_colab: trueto keep its Colab link.
Deferred: checking the notebook exists before Launch is shown
The maintainer wants a failsafe, so that Launch never opens a missing notebook. Where that check runs is not decided yet. Current thinking: an in-page script that shows Launch only when it finds the referenced notebook.
| Approach | How it works | For | Against |
|---|---|---|---|
| In-page failsafe (current thinking) | Launch starts hidden. A script requests the page's notebook, for example HEAD https://raw.githubusercontent.com/<repo>/<branch>/<path>.ipynb, and reveals the control only on success. raw.githubusercontent.com allows cross-origin requests and returns 404 for a missing repository (checked 2026-09-11) |
Accurate per page; catches a repository renamed or emptied after the build; no build change | One request to GitHub per page view (cacheable for the session); the control appears after load; readers without JavaScript, or where GitHub is blocked, never see it |
| Build-time check | The theme fetches the notebook repository's file list once per build, and renders Launch only on pages whose notebook is listed | Static, repeatable output; no requests from readers | Needs network during the build, and a GITHUB_TOKEN in CI (the unauthenticated GitHub API allows 60 requests an hour); goes stale if the repository changes after the build |
| Notebooks served from the site | Notebooks are published with the site (QuantEcon/quantecon-book-theme#359, or the fork's ipynb export), so the build knows which exist | No check needed, and no companion repositories | Relies on Colab opening a notebook by URL (the claim in QuantEcon/quantecon-book-theme#359, not verified here), and on every site publishing its notebooks |
Whichever approach is chosen:
- Fail closed: hide the control on a timeout or error.
- Keep the toolbar steady: no layout shift and no empty slot (the toolbar's optional slots use
empty:hidden). - Decide per page.
- Test the hidden state.
Acceptance criteria
- Launch (desktop toolbar and mobile overflow menu) renders only when
launch_notebook_repois set andlaunch_colabis true. With either unset, there is no Launch control and no empty toolbar slot. - The Colab URL is built from
launch_notebook_repo,launch_notebook_branch,launch_notebook_dirandlaunch_notebook_source_dir, and nothing is derived fromproject.github.launch_repo_suffixand the.mystrule are gone. - The options are declared in
template.ymland listed in docs/configuration.md. - docs/launch.md and the README explain the options, map them from the Sphinx keys, and say that a site without a notebook source shows no Launch.
-
tests/unit/launch-urls.test.mjscovers the new options. The visual fixture setslaunch_notebook_repoandlaunch_colabfor thelaunch-colabtest, and a new test asserts that no Launch control renders without them. - The CHANGELOG records the opt-in default and the renamed and removed options, as a breaking change for sites that relied on the guessed repository.
- The deferred existence check is either implemented as decided above, or split into its own issue before this one closes.
- After the release, live lecture-wasm shows no Launch link, and the
jb2build keeps its Colab link with the two new options.
Context
- Source: the 2026-09-11 book-theme parity study, rows F073 (Google Colab launch link) and F076 (notebook repository mapping).
- Why not
hide_launch: the first version of this issue proposed an opt-out option besidehide_tocandhide_search. The hide_toc and hide_search options are declared and documented but have no effect #213 shows those two options have no effect, and opt-out keeps dead links as the default. - Related, launch services: Feature: Add BinderHub support to Launch Notebook #26 (BinderHub), Feature: JupyterHub launch support — config-driven links (replacing the option removed in #87) #153 (JupyterHub links) and Feature: connect in-page compute to a running Jupyter server (Thebe
server:backend, incl. localhost) #154 (Thebe server). All of them need a notebook source, which the options above provide. - Related, config and checklist: Template options can only be scalars, so site templates pack lists and nested settings into YAML strings mystmd#112 (structured template options) and Lecture repos moving off the Sphinx theme have no checklist of what myst.yml and CI must now set #209 (migration checklist).
- Related, notebook hosting: QuantEcon/workspace-lectures#12 (notebook sync, which records that lecture-dp has no notebooks repository) and Update Colab badge URLs to support notebooks on gh-pages quantecon-book-theme#359 (notebooks served from the site).
- Overlap: open PR feat(compute): per-lecture live compute via an enable_live_compute site option #195 also edits
template.yml,app/types.ts, the docs andtheme.spec.ts, so whichever lands second rebases. - Out of scope (F076, latent, no lecture site affected): a sub-path inside a repository URL, and non-GitHub repository URLs, which the book theme warns about and skips (launch.py L51-L53).
Activity
mmcky commentedon Sep 11, 2026
Decision — 2026-09-11
Decided in the review of the #147 gate. The body is revised in place to match.
launch_notebook_repo) and a launch service is enabled (launch_colab: true). No repository name is guessed.launch_notebook_repobecomeslaunch.notebook.repo,launch_colabbecomeslaunch.colab). They move to nested settings once mystmd supports structured template options (QuantEcon/mystmd#112).launch_notebook_*says where the notebook lives;launch_colaband the future service keys (launch_binderhub_url,launch_jupyterhub_url) say what can open it.launch_repo_suffix, the.mystrule and the derivation fromproject.githubare removed.launch_repo_url,launch_branch,launch_notebooks_pathandlaunch_source_pathare renamed, as in the body's table.launch_notebook_repoonly if that repository exists (#209).chore(release): prepare v3.0.0 (#236)