Skip to content

Migrating from manubot

If you have an existing manubot manuscript built on rootstock and you want to move it to quartobot, here’s the translation. The pattern is preserved — prose source in git, auto-resolved citations, per-commit permalinks, PR-reviewed prose. What you change is the build pipeline and a few filename conventions.

  • Don’t delete anything. Migrate on a branch (or a separate worktree); keep the manubot setup intact until the new one renders correctly.
  • Decide the project shape. Most manubot manuscripts map cleanly onto Quarto’s manuscript template (single paper.qmd plus references). Longer works — theses, reviews, books in progress — map better onto the book template (chapter-per-file). Pick one; you can switch later, the file shape is the only thing that changes.
  • What carries over unchanged: your prose, your cite keys, your hand-curated references, your figures. What changes: the build pipeline, the metadata file’s shape, the directory layout.
Terminal window
uv tool install git+https://github.com/quartobot/quartobot
quartobot --version

Puts quartobot on your user PATH (~/.local/bin/ typically). Quarto’s pre-render subprocess needs to find it there. See Install for uvx, editable, and post-v0.1-tag pip install paths.

In the same repo, alongside your existing content/, build/, and ci/ directories:

Terminal window
quartobot init

init writes:

  • _quarto.yml with the pre-render hook wired to quartobot resolve
  • references.bib (seed for hand-curated entries — empty)
  • _version-banner.html.template + _version-banner.html (dev placeholder)
  • .github/workflows/render.yml (ten-line caller of the upstream reusable workflow)
  • .github/workflows/pr-closed.yml (preview teardown)
  • .gitignore augments

For a book project, pass --project-type book — same files, plus chapters/ is where your content lives.

Terminal window
quartobot init --project-type book

Manubot’s content/01-abstract.md, 02-introduction.md, … get concatenated at build into one manuscript. Quarto’s manuscript template uses one paper.qmd (or whatever you name it) for the same thing. The mechanical translation:

Terminal window
# Order matters — match manubot's numeric prefix order.
cat content/*.md > paper.qmd

Then move the YAML front-matter from content/metadata.yaml into the top of paper.qmd between --- fences (see Step 4).

The .md/.qmd syntax overlap is high enough that prose usually needs no edits. Things to spot-check after the concat:

  • Heading levels. Manubot expects # for the document title and ## for top-level sections; Quarto’s manuscript template treats the YAML title: field as the title and uses # for top-level sections. Drop the first # Title line and let Quarto render the title from the YAML.
  • Cite keys. No change — @doi:, @pmid:, @arxiv:, @isbn: etc. all work identically. Bare DOIs (@10.1371/…) also work.
  • Figure references. Manubot uses ![](images/foo.png); Quarto adds named cross-references via {#fig-foo}. If you want auto-numbered figure cross-references, add the ID; if your prose says “Figure 3” by hand, no change needed.
  • Math. Both use $…$ and $$…$$. No change.

Rename your manubot content files into chapters/:

Terminal window
mkdir -p chapters
for f in content/[0-9]*.md; do
base=$(basename "$f" .md)
# Drop the leading "01-" / "02-" prefix if you want clean URLs;
# keep it if you want to preserve manubot's filenames.
cp "$f" "chapters/${base#[0-9]*-}.qmd"
done

Edit _quarto.yml to list the chapters in order under book.chapters:. Move metadata.yaml content into the book: block in _quarto.yml (see Step 4).

Manubot’s content/metadata.yaml looks like:

title: My manuscript title
keywords:
- reproducibility
authors:
- github: alice
name: Alice Author
initials: AA
orcid: 0000-0000-0000-0000
email: alice@example.org
corresponding: true
affiliations:
- Department of Examples, University of Demonstration

Quarto’s equivalent goes either in the file’s YAML front-matter (for the manuscript shape) or under book: in _quarto.yml (for the book shape). The field names mostly map:

title: "My manuscript title"
keywords:
- reproducibility
author:
- name: Alice Author
affiliation: Department of Examples, University of Demonstration
orcid: 0000-0000-0000-0000
email: alice@example.org
corresponding: true

Differences worth flagging:

  • authors:author: (singular key, still takes a list — Quarto’s convention).
  • github: and initials: don’t have direct equivalents. Quarto doesn’t render them; if you want them on the manuscript, add them in an author block extension or drop them. Manubot uses these for contribution attribution in the rendered author block — see Quarto’s attribution: field for a similar surface.
  • affiliations: (list per author in manubot) → affiliation: (string, singular) for the simple case, or affiliations: (list of refs into a top-level affiliations: block) for multiple affiliations per author. Quarto’s affiliation reference shape is documented at quarto.org/docs/journals/authors.html.
  • funders: / acknowledgments: go in the front-matter the same way manubot puts them in metadata; Quarto reads them per the journal template you’re targeting.

Step 5 — Move your hand-curated references

Section titled “Step 5 — Move your hand-curated references”

Manubot’s content/manual-references.json (CSL JSON) or content/manual-references.yaml (CSL YAML) or content/manual-references.bib all map onto references.bib (BibTeX) or stay as their original format — pandoc citeproc reads .bib, .json (CSL JSON), and .yaml (CSL YAML) interchangeably.

The simplest move:

Terminal window
# If you had a .bib already, just copy it.
cp content/manual-references.bib references.bib

Or convert CSL JSON to BibTeX with pandoc-citeproc:

Terminal window
pandoc -f csljson -t biblatex content/manual-references.json -o references.bib

Then make sure _quarto.yml lists it under bibliography:. The template quartobot init writes already does:

bibliography:
- references.bib # hand-curated
- references.json # auto-resolved by `quartobot resolve`

If you had manual-references.json populated by manubot’s resolver runs (not hand-curated), discard it. The pre-render hook regenerates the auto-resolved references.json on next render from the cite keys in your prose.

Delete build/ and the manubot CI workflow:

Terminal window
git rm -r build/
git rm ci/build.yaml 2>/dev/null # or wherever your manubot workflow lives
git rm .github/workflows/manubot.yaml 2>/dev/null

quartobot init already wrote .github/workflows/render.yml — a ten-line caller of the upstream reusable workflow. That workflow handles render → permalink staging → gh-pages deploy → sticky PR comment, the same surface manubot’s build/build.sh + build/webpage.sh covered.

The deployed URL layout is preserved: https://<owner>.github.io/<repo>/v/<sha>/ for per-commit snapshots, https://<owner>.github.io/<repo>/ for latest main, https://<owner>.github.io/<repo>/pr/<n>/ for open PR previews. Existing links into your manuscript’s snapshot URLs keep working.

Terminal window
quarto render

The pre-render hook runs quartobot resolve first, writes references.json. Then pandoc renders the document; citeproc reads both bibliographies. Open index.html (manuscript) or _book/index.html (book) and check that:

  • Every @doi: / @pmid: / @arxiv: cite resolved (no [Unresolved citation: …] markers).
  • Hand-curated cites from references.bib rendered.
  • Figures show up.
  • The version banner is the dev placeholder (gets replaced by CI on push to main).

quartobot validate . runs the same checks the CI lint step does:

Terminal window
quartobot validate .

Expect 5 checks; failures usually mean the pre-render line in _quarto.yml is malformed or references.json isn’t in the bibliography: list.

Terminal window
git add .
git commit -m "Migrate to quartobot"
git push

CI takes it from there. On first push to main, enable GitHub Pages in Settings → Pages → Source: GitHub Actions (or “Deploy from a branch → gh-pages” depending on which reusable workflow path you’re on). If the manubot setup was already deploying to gh-pages with the same /v/<sha>/ layout, the deploy slots in without breaking existing snapshot URLs.

Once the new pipeline has rendered cleanly on main:

  • content/ directory
  • build/ directory
  • ci/ directory (if manubot-specific)
  • Old manubot workflow files
  • Any webpage/ source-controlled checkout (the gh-pages branch is managed by CI now)

Keep the gh-pages branch intact — it has your historical snapshots at /v/<old-sha>/, and the new pipeline writes new ones alongside.