Summary
mystmd currently lacks the numbering and cross-reference machinery needed to faithfully reproduce a printed academic book in HTML. This issue collects three closely-related gaps we hit while converting Dynamic Programming Volume I (Sargent & Stachurski) from LaTeX to MyST Markdown — see QuantEcon/book-dp1#336 and the downstream issues #343, #345, #346.
The three gaps share a common root: MyST's numbering and cross-reference roles do not give book authors enough control to match a published volume's numbering scheme. Books (unlike papers or web articles) need:
- chapter / appendix / part numbering that flows through cross-references,
- theorem-class counters that can be offset, shared, or formatted per project conventions,
- equation numbering that distinguishes labelled vs unlabelled display math.
We believe these belong in mystmd core (or a first-party plugin) rather than as per-project post-processors. Without them, every long-form book project ends up shipping its own ad-hoc Python sed scripts — exactly what we are doing today in book-dp1 and previously in book-dp2.
Gap 1 — Chapter cross-references render the title, not "Chapter N"
Symptom. Given a chapter labelled c-rdps and a cross-reference In Chapter {ref}\c-rdps``, MyST renders "In Chapter Recursive Decision Processes". Print convention — and the corresponding PDF — renders "In Chapter 6".
Why {numref} does not solve this today. Top-level pages are not enumerated targets in MyST's current model; {numref} only works against figures, tables, equations, and prf:* blocks. Even if pages were enumerated, the appendix collision matters:
| label |
TOC group |
desired render |
c-rdps |
Chapters |
"Chapter 6" |
c-areal |
Appendix |
"Appendix" (or "Appendix A") |
Other front/back-matter pages (preface, common_symbols, licensing) have no labels today but in principle should be referenceable as e.g. "the Preface" — i.e. by role within the book, not by number.
Proposed mystmd feature.
- Treat top-level TOC entries as enumerable, with the enumerator scoped to the TOC group ("Chapters", "Appendix", "Parts", …).
- Expose a per-group
enumerator template, e.g.
toc:
- title: "Chapters"
enumerator: "Chapter %s"
children: [...]
- title: "Appendix"
enumerator: "Appendix %s" # or just "Appendix" for a single-entry group
children: [...]
- Make
{numref}\c-rdps`render the enumerator-formatted string, and make a new fallback (e.g.{chapref}` or auto-detect) collapse the prose word + number where the source already wrote "Chapter".
- Provide a clean way to refer to unnumbered pages by display title or by an explicit override (
{ref}\c-preface` `), without falling back to the page's heading text in a way that produces ungrammatical output ("In Chapter Preface").
A non-trivial design point: the cross-reference role needs to know the TOC group of its target, which means the build needs to thread group/parent information into the reference resolver.
Gap 2 — Theorem / proposition / lemma numbers do not match the printed volume
Symptom. prf:theorem, prf:proposition, prf:lemma, etc. each maintain an independent per-chapter counter starting at 1. The printed book's counters often:
- share a single counter across multiple types (e.g. theorems, propositions, lemmas all draw from one sequence),
- start at non-1 offsets in some chapters (continuation across parts),
- format as
Theorem 6.2 (chapter.local) where the chapter prefix should match Gap 1's enumerator.
We hit the identical problem in book-dp2 and could not resolve it cleanly inside the project — fundamentally requires upstream control.
Proposed mystmd feature. Configuration knobs on the proof-numbering renderer:
numbering:
proof:
counter: shared # or: per-type (current default)
types: [theorem, proposition, lemma, corollary]
offset:
ch_fps: 0
ch_mdps: 5 # start chapter 5 at theorem 6
template: "{chapter}.{n}" # uses Gap 1's chapter enumerator
This need not solve every numbering scheme, but the three knobs (shared-counter, offset, format-template-with-chapter) cover the common cases in mathematical books.
Gap 3 — Equation numbering does not distinguish labelled vs unlabelled display math
Symptom. LaTeX distinguishes equation (numbered) from equation* (unnumbered) and treats $$ ... $$ without a \label as unnumbered. After pandoc → MyST conversion, every display-math block tends to get a sequential number, which both clutters the page and breaks alignment with the PDF's equation numbers.
Proposed mystmd feature.
- Default: only number display math that has an explicit label (matches LaTeX
equation* semantics for unlabelled blocks).
- Provide
:no-number: / :number: overrides on the math directive.
- Allow a per-chapter offset / counter format consistent with Gap 1's enumerator (
(6.12) instead of (12)).
Implementation path: a mystmd extension for "book-style" numbering
Rather than land all of this in mystmd core, a natural first step is to develop a first-party extension that opts a project into book-style numbering as a unit — analogous to sphinx-multitoc-numbering, which exists precisely because Sphinx's default toctree numbering doesn't fit multi-part books.
Sketch:
- Package name (working title):
mystmd-book-numbering (or similar), shipped from QuantEcon/mystmd initially.
- Activation via
myst.yml:
extensions:
- book-numbering
numbering:
style: book # turns on the bundled scheme
- The extension owns:
- TOC-group enumerators ("Chapter %s", "Appendix %s") and the
{numref} / {ref} rendering hook for top-level page targets (Gap 1).
- Proof-counter sharing, offsets, and
{chapter}.{n} formatting (Gap 2).
- Labelled-only equation numbering with chapter-prefixed format (Gap 3).
- Benefits:
- Decouples experimentation from
mystmd release cadence — we can iterate on the QuantEcon fork.
- Easy on/off for book authors who want it; zero impact on article authors who don't.
- Provides a clear migration path: once stable, the extension's behaviour can be folded into core (or stay as the supported plugin, the way
sphinx-multitoc-numbering did).
- Reference prior art to study:
sphinx-multitoc-numbering (numbering)
sphinx-proof (proof-counter implementation)
sphinx-book-theme (theme-level book affordances)
If we go this route, the umbrella issue becomes: agree the design above, then implement in mystmd-book-numbering, then dogfood on book-dp1 and book-dp2.
Summary
mystmdcurrently lacks the numbering and cross-reference machinery needed to faithfully reproduce a printed academic book in HTML. This issue collects three closely-related gaps we hit while converting Dynamic Programming Volume I (Sargent & Stachurski) from LaTeX to MyST Markdown — see QuantEcon/book-dp1#336 and the downstream issues #343, #345, #346.The three gaps share a common root: MyST's numbering and cross-reference roles do not give book authors enough control to match a published volume's numbering scheme. Books (unlike papers or web articles) need:
We believe these belong in
mystmdcore (or a first-party plugin) rather than as per-project post-processors. Without them, every long-form book project ends up shipping its own ad-hoc Python sed scripts — exactly what we are doing today inbook-dp1and previously inbook-dp2.Gap 1 — Chapter cross-references render the title, not "Chapter N"
Symptom. Given a chapter labelled
c-rdpsand a cross-referenceIn Chapter {ref}\c-rdps``, MyST renders "In Chapter Recursive Decision Processes". Print convention — and the corresponding PDF — renders "In Chapter 6".Why
{numref}does not solve this today. Top-level pages are not enumerated targets in MyST's current model;{numref}only works against figures, tables, equations, andprf:*blocks. Even if pages were enumerated, the appendix collision matters:c-rdpsc-arealOther front/back-matter pages (
preface,common_symbols,licensing) have no labels today but in principle should be referenceable as e.g. "the Preface" — i.e. by role within the book, not by number.Proposed mystmd feature.
enumeratortemplate, e.g.{numref}\c-rdps`render the enumerator-formatted string, and make a new fallback (e.g.{chapref}` or auto-detect) collapse the prose word + number where the source already wrote "Chapter".{ref}\c-preface` `), without falling back to the page's heading text in a way that produces ungrammatical output ("In Chapter Preface").A non-trivial design point: the cross-reference role needs to know the TOC group of its target, which means the build needs to thread group/parent information into the reference resolver.
Gap 2 — Theorem / proposition / lemma numbers do not match the printed volume
Symptom.
prf:theorem,prf:proposition,prf:lemma, etc. each maintain an independent per-chapter counter starting at 1. The printed book's counters often:Theorem 6.2(chapter.local) where the chapter prefix should match Gap 1's enumerator.We hit the identical problem in book-dp2 and could not resolve it cleanly inside the project — fundamentally requires upstream control.
Proposed mystmd feature. Configuration knobs on the proof-numbering renderer:
This need not solve every numbering scheme, but the three knobs (shared-counter, offset, format-template-with-chapter) cover the common cases in mathematical books.
Gap 3 — Equation numbering does not distinguish labelled vs unlabelled display math
Symptom. LaTeX distinguishes
equation(numbered) fromequation*(unnumbered) and treats$$ ... $$without a\labelas unnumbered. After pandoc → MyST conversion, every display-math block tends to get a sequential number, which both clutters the page and breaks alignment with the PDF's equation numbers.Proposed mystmd feature.
equation*semantics for unlabelled blocks).:no-number:/:number:overrides on the math directive.(6.12)instead of(12)).Implementation path: a
mystmdextension for "book-style" numberingRather than land all of this in
mystmdcore, a natural first step is to develop a first-party extension that opts a project into book-style numbering as a unit — analogous tosphinx-multitoc-numbering, which exists precisely because Sphinx's default toctree numbering doesn't fit multi-part books.Sketch:
mystmd-book-numbering(or similar), shipped fromQuantEcon/mystmdinitially.myst.yml:{numref}/{ref}rendering hook for top-level page targets (Gap 1).{chapter}.{n}formatting (Gap 2).mystmdrelease cadence — we can iterate on the QuantEcon fork.sphinx-multitoc-numberingdid).sphinx-multitoc-numbering(numbering)sphinx-proof(proof-counter implementation)sphinx-book-theme(theme-level book affordances)If we go this route, the umbrella issue becomes: agree the design above, then implement in
mystmd-book-numbering, then dogfood onbook-dp1andbook-dp2.