Melbourne Bioinformatics Workbench Lesson Template (R Markdown)
August 3, 2026 · View on GitHub
The University of Melbourne fork of the Carpentries Workbench R Markdown lesson template. Use it to start a new MB training workshop whose episodes execute code at build time, so outputs, tables and plots are generated from the source rather than pasted in.
It differs from the upstream Carpentries template in two ways. It pins our theme fork,
uom-varnish, in config.yaml:
varnish: 'melbournebioinformatics/uom-varnish@main'
url: 'melbournebioinformatics.github.io/uom-varnish'
and it adds UoM institute codes to carpentry:, which selects the branding on the built site:
uom (University of Melbourne), mb (Melbourne Bioinformatics), mig (Melbourne Integrative
Genomics), wehi (Walter and Eliza Hall Institute), abacbs (Australian Bioinformatics and
Computational Biology Society). Keep both settings when you adapt this template.
Full contributor documentation lives in the MB tutorials wiki.
Which template do I want?
| Use when | |
|---|---|
workbench-template-md | Episodes are prose, screenshots and fenced code blocks that are shown, not run. Command-line tutorials, GUI walkthroughs, conceptual material. |
workbench-template-rmd (this one) | Episodes must execute code at build time. R, or Python via reticulate. |
Only pick this one if you actually need code to run. R Markdown lessons carry a pinned dependency set that has to be maintained, and every build has to install and run it.
Note about lesson life cycle stage
Although config.yaml states the life cycle stage as pre-alpha, the template is stable and
ready to use. The life cycle stage is preset to "pre-alpha" because that is the right setting
for a brand new lesson.
Create a new lesson from this template
Click Use this template at the top right of the repository page, then Create a new repository.
Name the repository in lowercase with dashes separating words, and make the name say what the
lesson is about plus either its focus or its technical level. intro-to-r is topic plus level;
rna-seq-counts-to-genes is topic plus scope. The name becomes the published URL, so it is worth
a minute of thought. A new lesson can start private and be made public later.
Configure the new lesson
- Enable GitHub Pages. Settings → Pages, build from the
gh-pagesbranch. That branch appears once the first build workflow has run, so check Actions if it is not there yet. - Fill in
config.yaml. Every field marked# FIXME:title,carpentry_description,created,keywords,contact,source, andlife_cycle(pre-alpha→betaonce the lesson is usable). Setcarpentry:to your institute code, and list your episode files in teaching order underepisodes:. Leave thevarnish:andurl:lines alone. - Rename
FIXME.Rprojto match the repository name. - Annotate the repository. On the landing page, click the cog next to About, tick "Use your
GitHub Pages website", and add topic tags:
lesson, the life cycle stage, and the language. - Adjust
CODE_OF_CONDUCT.md,CONTRIBUTING.mdandLICENSE.mdfor your project. - Replace this README with a description of your lesson, and delete these instructions.
Build and preview locally
Requires R and pandoc. One-time setup on your machine:
install.packages("pak")
options(repos = c(
carpentries = "https://carpentries.r-universe.dev",
CRAN = "https://cloud.r-project.org"
))
pak::pak(c("sandpaper", "pegboard", "tinkr"))
pak::pak("melbournebioinformatics/uom-varnish") # installs under the package name `varnish`
sandpaper::use_package_cache(prompt = FALSE)
We use pak rather than devtools, which has been split up and superseded. Then, from inside
the lesson repository:
sandpaper::serve() # live-reload preview on http://127.0.0.1:4321
sandpaper::build_lesson() # one-off build into site/
sandpaper::check_lesson() # structure and link validation
Dependencies
Two separate sets of packages, and mixing them up is the single most common problem people hit:
| Lives in | Contains | Installed by | |
|---|---|---|---|
| Build toolchain | your normal user library | sandpaper, pegboard, tinkr, varnish | you, with the pak block above |
| Lesson dependencies | renv/profiles/lesson-requirements/ in this repo | whatever the .Rmd episodes library() | sandpaper::manage_deps(), automatically |
sandpaper does not make itself the project's renv environment. It loads the lesson-requirements
renv profile only while rendering episodes, which is why your interactive session can still find
sandpaper.
Adding a package to an episode is therefore just: library(thepackage), rebuild, and commit the
changed renv/profiles/lesson-requirements/renv.lock. CI decides whether the lesson has pinned
dependencies purely by whether that file is in the repository, so if it is not committed the
lesson builds against whatever is current on the day.
⚠️ Never run
renv::init()orrenv::activate()in a lesson repository. Both write a root.Rprofilethat hijacks every R session in the repo into the lesson library, at which pointsandpaperappears to vanish. If that has already happened, delete.Rprofileand restart R.
The full explanation, including troubleshooting, is in Renv and dependencies.
Python episodes
episodes/python-with-reticulate.Rmd is a working example. Declare Python dependencies in the
episode's setup chunk and reticulate provisions an ephemeral environment with uv, fetching
both the interpreter and the packages:
```{r setup, include=FALSE}
Sys.setenv(RETICULATE_PYTHON = "managed")
library(reticulate)
py_require(c("pandas", "matplotlib"), python_version = "3.12", exclude_newer = "2026-08-01")
```
Nothing needs adding to the CI workflows for this to work. Delete the example episode, and its
entry in config.yaml, if your lesson is R only.
Writing episodes
Episodes live in episodes/*.Rmd, one per major section, 15 to 45 minutes each and never longer
than an hour. Every episode needs title, teaching and exercises in its frontmatter, plus
questions and objectives blocks at the top and a keypoints block at the end.
episodes/introduction.Rmd demonstrates every available block.
Callouts, challenges and solutions use Carpentries fenced divs. Fence depth must match exactly between the opening and closing markers, or pegboard fails and the block renders as plain text.