Project guidance for Claude Code (CLI, IDE, and the GitHub Action). The same conventions apply to GitHub Copilot --- see .github/copilot-instructions.md, which is the source of truth for style.
mds holds the mathematics that the Morrison-Lab data science courses assume: notation, algebra, calculus, linear algebra and vector calculus, as Quarto fragments. It renders on its own as a website, and course sites such as mlds link to its pages by URL, so a page's path and its #id anchors are an interface: renaming either breaks those links. The scaffolding came from the UCD-SERG qwt template.
Authoritative style guide: UCD-SERG Lab Manual (source: https://github.com/UCD-SERG/lab-manual).
index.qmd,chapters/,appendix-*.qmd--- Quarto source pagesreferences.qmd--- standalone reference page; excluded from the default website render (!references.qmdin_quarto-website.yml), so it isn't part of the normal site build_quarto.yml,_quarto-website.yml--- Quarto project + website config_extensions/--- vendored Quarto extensionslatex-macros/--- git submodule for shortcode/macro definitions (see.gitmodules)R/,man/,DESCRIPTION,NAMESPACE--- the project is also a small R packagereferences.bib--- BibTeX bibliographypage-navigation.html--- HTML include (format.html.include-after-body) that adds floating previous/next arrows in the page margins and highlights the navbar link for the current page; vendored fromMorrison-Lab/lbtviaMorrison-Lab/qwt. The previous/next order comes fromwebsite.sidebarin_quarto-website.yml, so add each new page to both the navbar and the sidebar, in the same position.offwhite.scss,theme-picker.html--- the website's Light / Off-white / Parchment / Dark theme dropdown (saved undermln-theme, shared with the slides and the other sites on this origin)styles.css--- website styling;styles-reveal.scss,qwt-reveal-toggle.html(the same dropdown for slides), and therevealjs-*.luafilters drive the reveal.js slide outputmath-xrefs.lua--- resolves@idcross-references written inside math (for example a\text{(@thm-spectral)}derivation annotation), which Quarto leaves as literal text; it numbers theorem-type divs and labelled equations the way Quarto does and writes the label ("Theorem 59"), linked in HTMLassets/,images/--- static image and asset files (site pages, docs, CI/PR screenshots).github/workflows/--- CI workflow definitions.github/scripts/--- helper scripts used by workflows.github/instructions/--- path-scoped Copilot rules that attach by file glob (see.github/copilot-instructions.md)CONTRIBUTING.md--- contributor guide_site/,_freeze/,.quarto/--- build artifacts (do not edit by hand)
Mirrors .github/copilot-instructions.md. Key points:
- Lists of 3+ items: use bullet lists rather than comma-separated prose. Always leave a blank line before a markdown bullet list (especially in
.qmdfiles). - Code chunks: HTML output folds code by default:
_quarto-website.ymlsetscode-fold: true(withcode-tools: true, so readers can show all code at once), as rme does. Keep the default when the output (plot, table) is the point and the code is incidental. Set#| code-fold: falseon tutorial code, short examples, code that is the main focus, and chunks where the console output is the main content. - R style: respect
.lintr.R. Runlintr::lint_dir()before declaring R changes done. - No nested calls in R:
lint-changed-lines.yamllints the R code and R chunks that a PR adds or edits, withlms::default_linters(nested_calls = TRUE). Itsnested_calls = TRUEsetting enforces the lab's no-nested-calls rule. The linters also flag base R functions that have tidyverse replacements. Run the same linters on a file before pushing withlintr::lint("file.qmd", linters = lms::default_linters(nested_calls = TRUE)). - Quarto chunks: prefer chunk options as YAML-style
#|directives, not as inliner, opt = valarguments. - Useful resources: a course, book or video that covers a topic mds teaches goes in the Further reading section of the matching page,
even when lds already lists it in a directory (Ezra, 2026-10-15).
Link the resource, and adapt it with attribution only when its license allows adapting.
See
track-useful-resources. - Page, section and subsection files nest by heading level (Ezra, 2026-11-03): a page's top-level
.qmdholds the YAML header, the macros include, every first-level heading, and an include of each first-level section's body. A section body holds its second-level headings and an include of each subsection's body, and so on down. Only the file for the level above holds a heading, so no file is a wrapper that adds one heading and one include. Apply it to a page when you touch it, not as a sweep. The rule is in psw's Writing for code review and software. - One term per
#def-div: define a single term in each definition div, and give each further term its own div and id, placed right after the first (or before it, if the first uses it) and linking to it. Aliases of one term ("also called ...") stay in the same div, in bold and in the div title. Put commentary in a separate#rem-div and each example in an#exm-div after the definition it illustrates. A theorem-type div states one result. Keep the old id on the original term (Ezra, 2026-10-12); see psw's Writing for teaching.
- Don't edit generated files:
README.mdis built fromREADME.Rmd;_site/and_freeze/are build outputs. - Local preview:
quarto preview(live reload). Full build:quarto render. When verifying a single edited page, render just that page (quarto render <file>.qmd --to html) rather than the whole site --- the/rendercommand is for the full build. - Submodules:
latex-macros/is the only git submodule (see.gitmodules). Rungit submodule update --init --recursiveafter cloning. - Spell check: words go in
inst/WORDLIST(see.github/workflows/check-spelling.yaml). Update the wordlist instead of disabling the check. - Link check: tuned in
lychee.toml; prefer fixing broken links over adding exceptions. - Other CI checks: workflows also verify bibliography DOIs (
check-bibliography-dois.yml) and flag non-standard characters (check-non-standard-chars.yaml). Fix the flagged source rather than relaxing the check. - A book with no DOI: add its key to
exclude-keysin.github/workflows/check-bibliography-dois.ymlin the same PR as itsreferences.bibentry and citations (mds#635). A separate exemption PR is flagged for a key no entry uses, and the entry's PR fails the check without it. - Previews skip the PDFs and Word files: on a pull request,
tools/skip_pdf_in_previews.py(apre-renderscript) removes thepdfanddocxformats unless the PR carries the labelpreview:pdforpreview:docx. The publish onmainbuilds both. With only the PDFs skipped, a preview took 89 of its 90 minutes, so the preview cap is 120 minutes (decided 2026-10-22, mds#447). - The Quarto freeze cache is kept across runs, and a changed subfile invalidates it (checked 2026-11-05 against
Morrison-Lab/ghav3, mds#631). Bothpublish.yml(freeze-cache: true) and the preview workflow restore_freezewithactions/cache, from the newest cache whose key matches.freeze: autohashes only a page's own file, so a changed subfile would otherwise keep serving stale results. gha'spreview/prune-stale-freeze.pyruns after the restore in both workflows. It reads the commit SHA out of the restored key and diffs that commit againstHEAD. It deletes the frozen results of every page that changed, that includes a changed file through any chain of{{< include >}}, or that mentions the file name of a changed non-page file (a data file, script or thelatex-macrospin). It resolves every path withPath.resolve(), so an include writtenmds/_subfiles/...reaches_subfiles/...through themds -> .symlink and counts as a dependency. If the key names no commit, or the commit cannot be fetched, it deletes the whole freeze. Before relying on it for a new include style (a{{< include >}}with a shortcode or variable in the path), check thatINCLUDE_REin that script matches it. Theclear freezerlabel discards the cache; a subfile edit no longer needs it. - Dependencies: Dependabot auto-updates the
latex-macrossubmodule and GitHub Actions (see.github/dependabot.yml); don't bump those by hand unless a PR needs it.
- Keep PRs scoped --- bug fixes shouldn't smuggle in refactors.
- Write commit messages and PR descriptions explaining the why, not just the what.
- Don't bypass CI failures (spell check, link check, lint, bibliography DOIs, non-standard chars) --- fix the underlying issue.
- Don't commit
_site/or_freeze/changes unless that is genuinely the intent of the PR.
The lab's cross-repository rules live in Morrison-Lab/ai-config,
which .claude/settings.json enables as the ai-config@Morrison-Lab plugin.
Enabling is not installing: a local session needs claude plugin install ai-config@Morrison-Lab once.
When the plugin is not loaded (for example, in a session rooted above this checkout),
read the rules from a clone of ai-config before content work, in particular:
shared/writing/--- definitions, derivation steps, fact-checking, cross-references, plain proseshared/coding/--- R style, ASCII punctuation in sourceskills/quarto-authoring/references/divs-and-spans.md--- no theorem-type div nested inside another
This repository is the canonical home for the math prerequisites
that Morrison-Lab/rme carries as appendices
(math-prereqs.qmd, algebra.qmd, calc-derivatives.qmd, calc-integrals.qmd and notation.qmd).
rme will drop those appendices and point readers here
(rme#1204).
- rme is a good first place to look for content, not an authority on content or style: much of it predates the lab's style rules. Check what you port, fix what is wrong, and bring it up to the current rules.
- Keep rme's
#ids, so rme's links can be repointed by changing only the path.
- Reformatting unrelated files.
- Inventing URLs or citations --- only use sources actually present in
references.bibor explicitly provided. - Showing readers source information when content comes from our own lab (e.g. "Source: new for Fall 2026", "written for Midterm 1", "from our lab"). Only external reference sources (textbooks, papers, external software) should be cited; internal lab provenance is unnecessary clutter for readers.
- Asking a person to check a citation you can check yourself.
The lab's reference books (for example Billingsley, Probability and Measure, 3rd ed.) are PDFs in
the private
Morrison-Lab/mlrrepository underbooks/; verify section, theorem, and page numbers against them before citing or reporting a citation as unchecked.
This repository follows the maintainer's cross-project agent rules in Morrison-Lab/ai-config. If your harness has not already loaded them (Claude Code loads them through the ai-config plugin), read AGENTS.md before starting work, and follow it alongside this file. This file's own instructions add to those rules, and win only where they are more specific.