You'll need to have the following software installed
- Python: can be installed via homebrew, conda, and directly from the python site
- R: can be installed via CRAN or homebrew
- Quarto: can be installed directly from the Quarto site or homebrew
- Doxygen: can be installed directly from the Doxygen site or homebrew
Building multi-lingual (R and Python) vignettes requires installing the vignettes' package dependencies. In Python, this is done via a virtual environment (local .venv)
python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
pip install git+https://github.com/StochasticTree/stochtree.git
And in R, this is typically done as a global system install, though you might also consider renv for managing project-specific R dependencies
Rscript -e 'install.packages(c("remotes", "devtools", "roxygen2", "ggplot2", "latex2exp", "decor", "pkgdown", "cpp11", "BH", "doParallel", "foreach", "knitr", "Matrix", "MASS", "mvtnorm", "rmarkdown", "testthat", "tgp", "here", "reticulate"), repos="https://cloud.r-project.org/")'
Rscript -e 'remotes::install_github("StochasticTree/stochtree", ref = "r-dev")'
Building the R API docs (roxygen2 / pkgdown) and C++ API docs (Doxygen) requires the stochtree source. Clone it into stochtree_repo/ at the repo root:
git clone --recurse-submodules https://github.com/StochasticTree/stochtree.git stochtree_repoWith the stochtree repo checked out and R dependencies installed (see above), run:
cd stochtree_repo
Rscript cran-bootstrap.R 0 1 0
cd ..
mkdir -p docs/R_docs/pkgdown
Rscript -e 'pkgdown::build_site_github_pages("stochtree_repo/stochtree_cran", dest_dir = "../../docs/R_docs/pkgdown", install = TRUE)'
cd stochtree_repo
Rscript cran-cleanup.R
cd ..cran-bootstrap.R 0 1 0 prepares a stochtree_cran/ subdirectory with the pkgdown config but without vignette source (vignettes are served by the Quarto site instead). cran-cleanup.R removes that temporary directory when done. The output is written to docs/R_docs/pkgdown/.
With the stochtree repo checked out and Doxygen installed (brew install doxygen on macOS), run:
sed -i '' 's|^OUTPUT_DIRECTORY *=.*|OUTPUT_DIRECTORY = ../docs/cpp_docs/|' stochtree_repo/Doxyfile
sed -i '' 's|^GENERATE_XML *=.*|GENERATE_XML = NO|' stochtree_repo/Doxyfile
sed -i '' 's|^GENERATE_HTML *=.*|GENERATE_HTML = YES|' stochtree_repo/Doxyfile
mkdir -p docs/cpp_docs/
cd stochtree_repo
doxygen Doxyfile
cd ..The output is written to docs/cpp_docs/doxygen/.
The vignettes live in the vignettes/ directory and are configured as a standalone Quarto website via vignettes/_quarto.yml. Each .qmd file uses {.panel-tabset group="language"} tabsets to present R and Python code side-by-side. Python cells are executed via reticulate; set the RETICULATE_PYTHON environment variable to point at your .venv interpreter if it isn't picked up automatically.
To render all vignettes at once:
cd vignettes
quarto renderTo render a single vignette:
cd vignettes
quarto render bart.qmdTo preview the vignette site locally with live reload:
cd vignettes
quarto previewThe rendered site is written to vignettes/_site/. Individual vignettes use freeze: auto in their frontmatter, so re-renders only re-execute cells whose source has changed. To force a full re-execution, delete vignettes/_freeze/ before rendering.
The python-api/reference/*.qmd files are generated by quartodoc from the stochtree package's docstrings. They are checked into the repo, so a normal quarto render will render whatever is already there. If you've updated docstrings in the stochtree Python package, regenerate them first:
source .venv/bin/activate
quartodoc buildThis reads the quartodoc: block in _quarto.yml and writes updated .qmd files to python-api/reference/. Run it from the repo root. After regenerating, commit the updated .qmd files and run quarto render as normal.
The CI workflow always runs quartodoc build before quarto render so the live site stays in sync with the latest package docstrings.
The full site (vignettes + Python API reference + embedded pkgdown/Doxygen) is built from the repo root with:
quarto renderThis requires pkgdown and Doxygen output to already exist at docs/R_docs/pkgdown/ and docs/cpp_docs/doxygen/ respectively (the CI workflow builds these before running quarto render). For iterating on vignettes alone, the cd vignettes && quarto render workflow described above is faster.
Freeze cache note: The vignette .qmd files use freeze: auto, so re-renders only re-execute cells whose source has changed. The freeze cache lives at _freeze/vignettes/ (top-level render) or vignettes/_freeze/ (standalone vignette render). If you switch between the two render modes, copy the cache to the appropriate location before rendering to avoid unnecessary re-execution.
The CI workflow (.github/workflows/docs.yml) handles the full build and deploys the output _site/ directory to the gh-pages branch.
The site is published in multiple versions from a single gh-pages branch: the latest release at the root (stochtree.ai/) and versioned sub-sites at stochtree.ai/v/<name>/ (e.g. the 0.5.0 release candidate at stochtree.ai/v/rc-0.5.0/). Each version is a branch of this documentation repo, and its build recipe is one entry in versions.json:
{
"name": "rc-0.5.0",
"docs_ref": "rc-0.5.0", // documentation branch to build
"cpp_ref": "main", "build_cpp": true, // C++ core source (+ whether to build Doxygen)
"r_ref": "r-rc-0.5.0", // R package source branch
"r_bootstrap": false, // run cran-bootstrap.R? (false = already packaged)
"r_pkg_path": "stochtree_repo", // installable package location
"py_ref": "py-rc-0.5.0", // Python package source branch
"target": "v/rc-0.5.0" // gh-pages sub-folder to deploy into
}The steps below are that rc-0.5.0 recipe made explicit for a local build. The key differences from the default build above: the R and Python sources come from packaged, single-language branches (r-rc-0.5.0 / py-rc-0.5.0) rather than the monorepo; the R branch is already a CRAN-friendly package at its root, so there is no cran-bootstrap.R step and pkgdown builds from the checkout root; and because those branches carry no C++ core, Doxygen is built from a separate checkout of the monorepo (cpp_ref).
# 1. Check out the documentation branch for this version
git checkout rc-0.5.0
# 2. R package source (already packaged at the checkout root — no cran-bootstrap)
git clone --recurse-submodules -b r-rc-0.5.0 \
https://github.com/StochasticTree/stochtree.git stochtree_repo
# 3. Python package source, installed into the venv
git clone --recurse-submodules -b py-rc-0.5.0 \
https://github.com/StochasticTree/stochtree.git stochtree_repo_py
source .venv/bin/activate
pip install ./stochtree_repo_py
# 4. C++ core for Doxygen, reused from the monorepo default branch (cpp_ref)
git clone --recurse-submodules -b main \
https://github.com/StochasticTree/stochtree.git stochtree_repo_cppThen build each component. Note pkgdown builds from r_pkg_path (the checkout root here) with an absolute dest_dir, and Doxygen runs against the stochtree_repo_cpp checkout:
# R API (pkgdown) — no cran-bootstrap; package is the checkout root
mkdir -p docs/R_docs/pkgdown
Rscript -e 'pkgdown::build_site_github_pages("stochtree_repo", dest_dir = file.path(getwd(), "docs/R_docs/pkgdown"), install = TRUE)'
# Install the RC R package so the vignettes can render against it
Rscript -e 'install.packages("stochtree_repo", repos = NULL, type = "source")'
# C++ API (Doxygen) — from the separate monorepo checkout
sed -i '' 's|^OUTPUT_DIRECTORY *=.*|OUTPUT_DIRECTORY = ../docs/cpp_docs/|' stochtree_repo_cpp/Doxyfile
sed -i '' 's|^GENERATE_XML *=.*|GENERATE_XML = NO|' stochtree_repo_cpp/Doxyfile
sed -i '' 's|^GENERATE_HTML *=.*|GENERATE_HTML = YES|' stochtree_repo_cpp/Doxyfile
mkdir -p docs/cpp_docs/
cd stochtree_repo_cpp && doxygen Doxyfile && cd ..
# Python API reference + the full site
quartodoc build
quarto renderquarto render writes the built site to _site/, which you can open directly to preview. The v/rc-0.5.0/ URL prefix is applied only at deploy time by CI (the target-folder in the deploy step), so a local render does not need it. To build a different version, read its entry in versions.json and substitute the corresponding refs, r_pkg_path, and r_bootstrap/build_cpp behavior.
CI does all of the above automatically for every entry in versions.json on each nightly run (and on release / manual dispatch); see "How CI builds every version" below.
.github/workflows/docs.yml reads versions.json and runs the build once per entry as a matrix job, deploying each into its target sub-folder with clean-exclude: v/** so the root build never wipes the sub-sites. Because GitHub Actions only fires scheduled/dispatch workflows from the default branch, the workflow on main is the one that drives all versions — a version branch's own copy of the workflow is not used for nightly builds. To add a version, add an entry to versions.json on main (and create the corresponding documentation branch and package source branches).