diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..8b98edda
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,13 @@
+---
+title: "Contributor Code of Conduct"
+---
+
+As contributors and maintainers of this project,
+we pledge to follow the [Carpentry Code of Conduct][coc].
+
+Instances of abusive, harassing, or otherwise unacceptable behavior
+may be reported by following our [reporting guidelines][coc-reporting].
+
+
+[coc-reporting]: https://docs.carpentries.org/topic_folders/policies/incident-reporting.html
+[coc]: https://docs.carpentries.org/topic_folders/policies/code-of-conduct.html
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 00000000..7632871f
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,79 @@
+---
+title: "Licenses"
+---
+
+## Instructional Material
+
+All Carpentries (Software Carpentry, Data Carpentry, and Library Carpentry)
+instructional material is made available under the [Creative Commons
+Attribution license][cc-by-human]. The following is a human-readable summary of
+(and not a substitute for) the [full legal text of the CC BY 4.0
+license][cc-by-legal].
+
+You are free:
+
+- to **Share**---copy and redistribute the material in any medium or format
+- to **Adapt**---remix, transform, and build upon the material
+
+for any purpose, even commercially.
+
+The licensor cannot revoke these freedoms as long as you follow the license
+terms.
+
+Under the following terms:
+
+- **Attribution**---You must give appropriate credit (mentioning that your work
+ is derived from work that is Copyright (c) The Carpentries and, where
+ practical, linking to ), provide a [link to the
+ license][cc-by-human], and indicate if changes were made. You may do so in
+ any reasonable manner, but not in any way that suggests the licensor endorses
+ you or your use.
+
+- **No additional restrictions**---You may not apply legal terms or
+ technological measures that legally restrict others from doing anything the
+ license permits. With the understanding that:
+
+Notices:
+
+* You do not have to comply with the license for elements of the material in
+ the public domain or where your use is permitted by an applicable exception
+ or limitation.
+* No warranties are given. The license may not give you all of the permissions
+ necessary for your intended use. For example, other rights such as publicity,
+ privacy, or moral rights may limit how you use the material.
+
+## Software
+
+Except where otherwise noted, the example programs and other software provided
+by The Carpentries are made available under the [OSI][osi]-approved [MIT
+license][mit-license].
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+## Trademark
+
+"The Carpentries", "Software Carpentry", "Data Carpentry", and "Library
+Carpentry" and their respective logos are registered trademarks of [Community
+Initiatives][ci].
+
+[cc-by-human]: https://creativecommons.org/licenses/by/4.0/
+[cc-by-legal]: https://creativecommons.org/licenses/by/4.0/legalcode
+[mit-license]: https://opensource.org/licenses/mit-license.html
+[ci]: https://communityin.org/
+[osi]: https://opensource.org
diff --git a/component-guide.md b/component-guide.md
new file mode 100644
index 00000000..460cd0cd
--- /dev/null
+++ b/component-guide.md
@@ -0,0 +1,214 @@
+---
+title: "Workbench Component Guide"
+---
+
+::::::::::::::::::: prereq
+
+### Find out More!
+
+This is the component guide for the workbench. For details on how to create
+components from [fenced divs][fenced-divs], read the [Callout Blocks section of
+"Episode Structure"](episodes.html#callout-blocks).
+
+::::::::::::::::::::::::::
+
+## Required Sections
+
+The workbench requires `objectives` and `questions` at the beginning and
+`keypoints` at the end of each episode.
+
+::::::::::::::::: objectives
+
+### OBJECTIVES (`objectives`)
+
+OBJECTIVES callouts are created with the `objectives` tag and outline what the
+learners should take away from the episode.
+
+::::::::::::::::::::::::::::
+
+::::::::::::::::: questions
+
+### QUESTIONS (`questions`)
+
+QUESTIONS callouts are created with the `questions` tag and offer questions for
+the learner before they start the episode.
+
+:::::::::::::::::::::::::::
+
+
+::::::::::::::::: keypoints
+
+### KEYPOINTS (`keypoints`)
+
+KEYPOINTS callouts are created with the `keypoints` tag and offer key takeaways
+from the episode to summarise what the learners should have learned.
+
+:::::::::::::::::::::::::::
+
+
+
+## Instructor Notes
+
+Special sections that only appear on the instructor view (use the button at the
+top right of the page to toggle).
+
+::::::::::::::::::: instructor
+
+### INSTRUCTOR NOTE (`instructor`)
+
+Instructor notes are created with the `instructor` tag
+
+::::::::::::::::::::::::::::::
+
+
+
+## Callout Blocks
+
+Sections to pause the narrative flow of an episode for learners to reflect.
+
+::::::::::::::::: callout
+
+### CALLOUT (`callout`)
+
+CALLOUT callouts are created with the `callout` tag and are an aside or comment.
+
+:::::::::::::::::::::::::
+
+::::::::::::::::: prereq
+
+### PREREQUISITES (`prereq`)
+
+PREREQUISITES callouts are created with the `prereq` tag and indicate things a
+learner needs before starting the episodes (e.g. data from a previous episode or
+and understanding of a particular concept).
+
+::::::::::::::::::::::::
+
+::::::::::::::::: checklist
+
+### CHECKLIST (`checklist`)
+
+CHECKLIST callouts are created with the `checklist` tag and are a way to more
+strongly emphasise particular steps.
+
+:::::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::::::: challenge
+
+### CHALLENGE (`challenge`)
+
+CHALLENGE callouts are created with the `challenge` tag and represent formative
+assessment opportunities for the learners to practice their skills.
+
+::::::::::::::::: hint
+
+### HINT (`hint`)
+
+HINT accordions are created with the `hint` tag and nested within
+`challenge` callouts. These offer more context for the challenge that can help
+the learner find the solution.
+
+::::::::::::::::::::::
+
+::::::::::::::::: solution
+
+### SOLUTION (`solution`)
+
+SOLUTION accordions are created with the `solution` tag and nested within
+`challenge` callouts. These provide the learners with the solution to the
+challenge so they can confirm their answers.
+
+::::::::::::::::::::::::::
+
+
+:::::::::::::::::::::::::::::::::::::::::::
+
+::::::::::::::::: discussion
+
+### DISCUSSION (`discussion`)
+
+DISCUSSION callouts are created with the `discussion` tag and represent an
+open-ended formative assessment in which the learners are expected to discuss
+a particular topic with other learners.
+
+::::::::::::::::::::::::::::
+
+::::::::::::::::: testimonial
+
+### TESTIMONIAL (`testimonial`)
+
+TESTIMONIAL callouts are created with the `testimonial` tag and are quotations
+from previous learners or instructors.
+
+:::::::::::::::::::::::::::::
+
+::::::::::::::::: spoiler
+
+### SPOILER (`spoiler`)
+
+SPOILER callouts are created with the `spoiler` tag and
+are a way to provide additional details/content
+that can be expanded and collapsed on demand.
+
+:::::::::::::::::::::::::
+
+
+### Tabbed Callouts
+
+::::::::::::::::: tab
+
+### Windows
+
+Some Windows instructions
+
+### Mac
+
+Maybe some for Mac
+
+### Linux
+
+And more for Linux users, including a code block:
+
+```python
+ print("Yay, tabs!")
+```
+
+:::::::::::::::::::::::::
+
+### Grouped Tabs
+
+The first tab specified is the default tab. Selecting a tab in one tab group changes the tab in
+the other group(s).
+
+::::::::::::::::::::: group-tab
+
+### Windows
+
+1
+
+### Mac
+
+2
+
+### Linux
+
+3
+
+:::::::::::::::::::::::::::::::
+
+::::::::::::::::::::: group-tab
+
+### Windows
+
+4
+
+### Mac
+
+5
+
+### Linux
+
+6
+
+:::::::::::::::::::::::::::::::
+
diff --git a/config.yaml b/config.yaml
new file mode 100644
index 00000000..3778dc67
--- /dev/null
+++ b/config.yaml
@@ -0,0 +1,92 @@
+#------------------------------------------------------------
+# Values for this lesson.
+#------------------------------------------------------------
+
+# Which carpentry is this (swc, dc, lc, or cp)?
+# swc: Software Carpentry
+# dc: Data Carpentry
+# lc: Library Carpentry
+# cp: Carpentries (to use for instructor traning for instance)
+carpentry: 'cp'
+
+# Overall title for pages.
+title: 'Introduction to The Carpentries Workbench'
+
+# Date the lesson was created (this is empty by default)
+created: ~
+
+# Comma-separated list of keywords for the lesson
+keywords: 'static site, lesson template, markdown, R, software'
+
+# Life cycle stage of the lesson
+# possible values: pre-alpha, alpha, beta, stable
+life_cycle: 'beta'
+
+# License of the lesson
+license: 'CC-BY 4.0'
+
+# Link to the source repository for this lesson
+source: 'https://github.com/carpentries/sandpaper-docs/'
+
+# Default branch of your lesson
+branch: 'main'
+
+# Who to contact if there are any issues
+contact: 'tobyhodges@carpentries.org'
+
+# Navigation ------------------------------------------------
+#
+# Use the following menu items to specify the order of
+# individual pages in each dropdown section. Leave blank to
+# include all pages in the folder.
+#
+# Example -------------
+#
+# episodes:
+# - introduction.md
+# - first-steps.md
+#
+# learners:
+# - setup.md
+#
+# instructors:
+# - instructor-notes.md
+#
+# profiles:
+# - one-learner.md
+# - another-learner.md
+
+# Order of episodes in your lesson
+episodes:
+- introduction.md
+- episodes.Rmd
+- editing.md
+- example.Rmd
+- deployment.md
+- update.md
+- pull-request.md
+
+# Information for Learners
+learners:
+- reference.md
+- setup.md
+- github-pat.md
+- component-guide.md
+- migrating-from-styles.md
+- style.md
+
+# Information for Instructors
+instructors:
+- instructor-notes.md
+
+# Learner Profiles
+profiles:
+- maintainer.md
+- instructor.md
+
+# Customisation ---------------------------------------------
+#
+# This space below is where custom yaml items (e.g. pinning
+# sandpaper and varnish versions) should live
+
+
diff --git a/deployment.md b/deployment.md
new file mode 100644
index 00000000..4f1176ab
--- /dev/null
+++ b/deployment.md
@@ -0,0 +1,119 @@
+---
+title: "Lesson Deployment"
+teaching: 5
+exercises: 0
+---
+
+::::::::::::::::::::::::::::: questions
+
+ - What is the two-step model of deployment?
+ - Why do we preserve both generated markdown and HTML?
+
+:::::::::::::::::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::: objectives
+
+ - Understand the two-step model for lesson deployment
+ - Understand how our lessons are deployed on GitHub
+
+::::::::::::::::::::::::::::::::::::::::
+
+## Building A Lesson
+
+Static site generators all know one thing: how to translate markdown to an HTML
+website. The Carpentries Lesson Infrastructure is no different in that it will
+generate an HTML website from markdown files using [pandoc]. The difference is
+how we handle the generated content to make your lesson portable and
+transferrable.
+
+### Working With Generated Content
+
+[The Carpentries has formally supported generated content from R lessons in the
+form of R Markdown files since 2016][rmd-blog] and we are working on a solution
+to incorporate generated content from other languages in the future. If you do
+not use generated content in your lesson, you can skip this section.
+
+The default paradigm for R Markdown is to first generate markdown output from
+the R Markdown document, convert it to HTML, and then discard the generated
+markdown output.
+
+![Source: "Teaching In Production" by Dr. Allison Horst,
+](https://github.com/rstudio-education/teaching-in-production/raw/master/slides/images/rmd_flowchart.png){alt="A
+stylized flowchart with 'good ideas', 'code', and 'data' flowing into '.Rmd',
+transformed to '.md' via 'knitr', and then transformed to 'html', 'pdf', and
+'docx' via 'pandoc'. There is an illustration of a hedgehog knitting a sock to
+the left and a rabbit wearing the other sock on the right."}
+
+However, this default behavior for generated content is not conducive for
+collaboration on lessons because the outputs often live in the same place as
+the source files. Moreover, if any changes occur in the software used to
+generate content, inspecting the differences between two HTML files is
+difficult because of markup. We created the {sandpaper} package to alleviate
+these downsides by clearly separating the generated content from the source
+material by taking advantage of a two-step model of deployment.
+
+### The Two-Step Model of Deployment
+
+To alleviate the downsides of working with generated content, The Carpentries
+Workbench employs a two-step model of deployment when you run
+`sandpaper::build_lesson()`
+
+1. Take any source files with content that needs to be interpreted (e.g.
+ R Markdown) and **render them to markdown** in a staging area ignored by git.
+2. Apply the HTML style to the markdown files in the staging area to create the
+ lesson website.
+
+![The two-step model of lesson deployment](https://zkamvar.github.io/stunning-barnacle/img/local-flow.dot.svg){alt='Diagram showing the process of `build_lesson(rebuild = TRUE)`, starting from R Markdown to Markdown and finally to HTML. R Markdown is highlighted as being the only element tracked by git.'}
+
+All of the generated content lives in the `site/` folder, and importantly: it
+is all cached and ignored by git. Ignoring generated content locally means that
+the source of truth for these files is no longer dependent on the maintainer's
+local setup.
+
+The reason we have this model is also for portability. It's because markdown
+output is a lot easier to audit than HTML when something goes wrong, rendered
+markdown can be transferred to other contexts (e.g. books or blogposts), and we
+can swap out the generators without needing to rewrite the entire pipeline.
+
+:::::::::::::: callout
+
+#### Did you know?
+
+When the lesson is pushed to GitHub, all of the generated content IS stored in
+separate branches so that we can provide a way for you to audit changes from
+pull requests.
+
+::::::::::::::::::::::
+
+## Deploying On GitHub
+
+For historical reasons, GitHub used the Jekyll static site generator to deploy
+their documentation websites, but because we no longer use Jekyll, we we deploy
+our sites in a different manner.
+
+On GitHub, we store generated content in two orphan branches called
+`md-outputs` and `gh-pages` for the generated markdown and html, respectively.
+We use [GitHub Actions Workflows][gh-workflows] to build, validate, and deploy
+our lessons on GitHub pages. Because the markdown and HTML outputs are preserved
+in the git history, we can tag and preserve them for archiving.
+
+These workflows are the source of truth for the lessons and will keep your
+lesson up-to-date with the latest version of the HTML template. Moreover, each
+week, these workflows will check for updates and, if there are any, a pull
+request will be created to ensure you are using the latest versions. You can
+[read more about updating your workflows in the Maintenance chapter](update.Rmd).
+
+If you use R Markdown in your lesson, you will notice that for every pull
+request (PR), a GitHub bot comments on your pull requests informing you about
+what content has changed and gives you a link to the differences between the
+current state of the `md-outputs` branch and the proposed changes. You can find
+out more about this in the [Pull Request chapter](pull-request.md).
+
+:::::::::::::::::::::::::::::: keypoints
+
+ - Lessons are built using a two-step process of caching markdown outputs and then building HTML from that cache
+ - We use GitHub Actions to deploy and audit generated lesson content to their websites
+
+::::::::::::::::::::::::::::::::::::::::
+
+
diff --git a/editing.md b/editing.md
new file mode 100644
index 00000000..5dce2f88
--- /dev/null
+++ b/editing.md
@@ -0,0 +1,447 @@
+---
+title: "Editing a {sandpaper} lesson"
+teaching: 5
+exercises: 0
+---
+
+:::::::::::::::::::: questions
+
+ - What is the folder structure of a lesson?
+ - How do you download an existing {sandpaper} lesson?
+
+:::::::::::::::::::::::::::::
+
+:::::::::::::::::::: objectives
+
+ - Understand how to clone an existing lesson from GitHub
+ - Use `sandpaper::build_lesson()` to preview a lesson
+ - Update the configuration for a lesson
+ - Rearrange the order of episodes
+
+:::::::::::::::::::::::::::::::
+
+
+If you want to edit and preview a full lesson using {sandpaper}, this is the
+episode for you. If you want to create a new lesson, head back to the episode
+for [Creating a New Lesson](introduction.html). I believe it's beneficial to
+experience editing a fully functional lesson, so you will edit THIS lesson. The
+first step is to fork and clone it from GitHub:
+
+## Fork and Clone a Lesson {#create-from-github}
+
+If you are familiar with the process of forking and cloning, then you may fork
+and clone as you normally do. If you would like a reminder, here are the steps:
+
+1. Think about a place on your computer where you want to work on your fork
+ of the lesson (e.g. `~/Documents/Lessons/`) and make sure that folder exists.
+
+2. Go to https://github.com/carpentries/sandpaper-docs/fork/ to fork the repository
+ to your account
+
+3. (recommended) When creating your fork, you should **uncheck** "Copy the
+ `main` branch only" checkbox.
+ ![](fig/fork-dialogue.png){alt="screenshot of the 'create a new fork' page with the 'Copy the main branch only' checkbox highlighted in yellow"}
+
+4. In the shell and use this command to clone this repository to your working
+ directory, replacing `` with your username
+ ```bash
+ cd ~/Documents/Lessons/
+ git clone git@github.com:/sandpaper-docs.git
+ cd sandpaper-docs
+ ```
+
+::::::::::::::: callout
+
+### One-step fork with R
+
+If you use R and you also use an HTTPS protocol, you might be interested to know
+that the above three steps can be done in a single step with the {usethis}
+package via the GitHub API:
+
+```r
+usethis::create_from_github("carpentries/sandpaper-docs", "~/Documents/Lessons/")
+```
+
+:::::::::::::::::::::::
+
+In the next section, we will explore the folder structure of a lesson.
+
+:::::::::::::::::::::::::::: challenge
+
+### Preview the Lesson
+
+1. Open the lesson in RStudio (or whatever you use for R)
+2. Use the keyboard shortcut ctrl + shift + b
+ (cmd + shift + b on macOS) to build and preview this lesson (or
+ type `sandpaper::build_lesson()` in the console if you are not using RStudio)
+3. Open THIS file (`episodes/editing.md`) and add step 4: preview the lesson again.
+
+What do you notice?
+
+::::::::: solution
+
+What you should notice is that the only file updated when you re-render the
+lesson is the file you changed (`episodes/editing.Rmd`).
+
+:::::::::::::::::
+::::::::::::::::::::::::::::::::::::::
+
+## Folder Structure
+
+:::::::::::::::: callout
+
+### :construction: This May Change :construction:
+
+The exact folder structure still has the possibility to change based on user
+testing for the front-end of the lesson website.
+
+::::::::::::::::::::::::
+
+The template folder structure will contain markdown files arranged so that they
+match what we expect the menubar for the lesson should be. All folders and files
+with an arrow `<-` are places in the lesson template you will be modifying:
+
+```
+|-- .gitignore # | Ignore everything in the site/ folder
+|-- .github/ # | Configuration for deployment
+|-- episodes/ # <- PUT YOUR EPISODE MARKDOWN FILES IN THIS FOLDER
+|-- instructors/ # <- Information for Instructors (e.g. guide.md)
+|-- learners/ # <- Information for Learners (e.g. reference.md and setup.md)
+|-- profiles/ # <- Learner and/or Instructor Profiles
+|-- site/ # | This is a "scratch" folder ignored by git and is where the rendered markdown files and static site will live
+|-- config.yaml # <- Use this to configure lesson metadata
+|-- index.md # <- The landing page of your site
+|-- CONTRIBUTING.md # | Carpentries Rules for Contributions (REQUIRED)
+|-- CODE_OF_CONDUCT.md # | Carpentries Code of Conduct (REQUIRED)
+|-- LICENSE.md # | Carpentries Licenses (REQUIRED)
+`-- README.md # <- Introduces folks how to use this lesson and where they can find more information.
+```
+
+This folder structure is heavily opinionated towards achieving our goals of
+creating a lesson infrastructure that is fit for the purpose of delivering lesson
+content for not only Carpentries instructors, but also for learners and
+educators who are browsing the content after a workshop. It is not designed to
+be a blog or commerce website. Read the following sections to understand the
+files and folders you will interact with most.
+
+All source files in {sandpaper} are written in [pandoc]-flavored markdown and
+all require yaml header called `title`. Beyond that, you can put anything in
+these markdown files.
+
+## `config.yaml`
+
+This configuration file contains global information about the lesson. It is
+purposefully designed to only include information that is editable and
+relevant to the lesson itself and can be divided into two sections: information
+and organization
+
+### Information
+
+These fields will be simple key-pair values of information used throughout the episode
+
+carpentry
+: The code for the specific carpentry that the lesson belongs to (swc, dc, lc, cp, incubator, lab)
+
+carpentry_description
+: (Optional) Full organisation name. Not needed when carpentry is swc, dc, lc, cp, incubator, or lab.
+
+::::::::::: callout
+
+### Adding a custom logo
+
+The "carpentry" variable works with the {varnish} package to control the logo displayed on your lesson. You can display your own logo by
+
+1. Adding the logo file as SVG (e.g. 'ice-cream-logo.svg') to your fork of {varnish} in the `inst/pkgdown/assets/assets/images` folder.
+1. Setting "carpentry" to match the beginning of the name of your logo file. E.g. to use the `ice-cream-logo.svg` file given above, "carpentry" should be set to 'ice-cream'.
+1. Adding 'varnish: [YOUR-GITHUB-USERNAME]/varnish' to the Customization section of your lessons `config.yaml` file.
+
+The rendered lesson will display your logo file with alternative text that matches the value of "carpentry". For more informative alternative text, you can set "carpentry_description" to your organisation's full name. E.g. "Ice Cream Carpentry" instead of "ice-cream".
+
+:::::::::::::::::::
+
+
+title
+: The main title of the lesson
+
+life_cycle
+: What life cycle is the lesson in? (pre-alpha, alpha, beta, stable)
+
+license
+: The license the lesson is registered under (defaults to CC-BY 4.0)
+
+source
+: The github source of the lesson
+
+branch
+: The default branch
+
+contact
+: Who should be contacted if there is a problem with the lesson
+
+### Organization
+
+These fields match the folder names in the repository and the values are a list of
+file names in the order they should be displayed. By default, each of these fields
+is blank, indicating that the default alphabetical order is used. To list items,
+add a new line with a hyphen and a space preceding the item name (`- `). For
+example, if I wanted to have the episodes called "one.md", "two.Rmd", "three.md",
+and "four.md" in numerical order, I would use:
+
+```yaml
+episodes:
+- one.md
+- two.Rmd
+- three.md
+- four.md
+```
+
+Below are the four possible fields {sandpaper} will recognize:
+
+episodes
+: The names of the episodes (main content)
+
+instructors
+: Instructor-specific resources (e.g. outline, etc)
+
+learners
+: Resources for learners (e.g. Glossary terms)
+
+profiles
+: Learner profile pages
+
+
+::::::::::::::::::::::::::::::: challenge
+
+### Configuring Episode Order
+
+Open `config.yaml` and change the order of the episodes. Preview the lesson
+after you save the file. How did the schedule change?
+
+::::::::::::::::: solution
+
+The episodes appear in the same order as the configuration file and the timings
+have rearranged themselves to reflect that.
+
+::::::::::::::::::::::::::
+::::::::::::::::::::::::::::::::::::::::::
+
+## `episodes/`
+
+This is the folder where all the action is. It contains all of the episodes,
+figures, and data files needed for the lesson. By default, it will contain an
+episode called introduction.Rmd. You can edit this file to use as your
+introduction. To create a new Markdown episode, use the folowing function:
+
+```r
+sandpaper::create_episode_md("Episode Name")
+```
+
+This will create a Markdown episode called `episode-name.md` in the
+`episodes/` directory of your lesson, pre-populated with objectives,
+questions, and keypoints. The episode will be added to the end of the `episodes:`
+list in `config.yaml`, which serves as the table of contents.
+
+If you want to create an episode, but are not yet ready to render or publish it,
+you can create a draft using the `draft_episode` family of functions:
+
+```r
+sandpaper::draft_episode_rmd("Visualising Data")
+```
+
+This will create an R Markdown episode called `visualising-data.Rmd` in the
+`episodes/` directory of your lesson, but it will NOT be added to `config.yaml`,
+allowing you to work on it at your own pace without the need to publish it.
+
+When you are ready to publish an episode or want to move an existing episode to
+a new place, you can use `move_episode()` to pull up an interactive menu for
+moving the episode.
+
+```r
+sandpaper::move_episode("visualising-data.Rmd")
+```
+
+```output
+βΉ Select a number to insert your episode
+(if an episode already occupies that position, it will be shifted down)
+
+1. introduction.md
+2. episode-name.md
+3. [insert at end]
+
+Choice:
+```
+
+::::::::::::::::: callout
+
+### Should I use R Markdown or Markdown Episodes?
+
+All {sandpaper} lessons can be built using Markdown, R Markdown, or a mix of
+both. If you want to dynamically render the output of your code via R (other
+languages will be supported in the future), then you should use R Markdown, but
+if you do not need to dynamically render output, you should stick with Markdown.
+
+Sandpaper offers four functions that will help with episode creation depending
+on your usage:
+
+| R Markdown | Markdown |
+| ---------------------- | --------------------- |
+| `create_episode_rmd()` | `create_episode_md()` |
+| `draft_episode_rmd()` | `draft_episode_md()` |
+
+
+:::::::::::::::::::::::::
+
+## `instructors/`
+
+This folder contains information used for instructors only. Downloads of code
+outlines, aggregated figures, and slides would live in this folder.
+
+## `learners/`
+
+All the extras the learner would need, mostly a setup guide and glossary
+live here.
+
+The glossary page is populated from the `reference.md` file in this folder.
+The format of the glossary section of the `reference.md` file is a heading title
+`## Glossary` followed by [a definition list](https://pandoc.org/MANUAL.html#definition-lists).
+Definition lists are formatted as two lines for each term, the first
+includes the term to be defined and then the second line starts with a ":"
+and a space then the definition.
+i.e.
+
+```markdown
+term
+: definition
+```
+
+term
+: definition
+
+## `profiles/`
+
+Learner profiles would live in this folder and target learners, instructors, and
+maintainers alike to give a focus on the lesson.
+
+## `index.md`
+
+This is the landing page for the lesson. The schedule is appended at the bottom
+of this page and this will be the first page that anyone sees.
+
+## `README.md`
+
+This page gives information to maintainers about what to expect inside of th
+repository and how to contribute.
+
+## Making your lesson citable
+You can add information about how people should cite your lesson by adding a citation file to your lesson repository. If the root folder of your lesson project includes a file called `CITATION` or `CITATION.cff`, the _'Cite'_ page footer of your lesson site will link to this file.
+
+We recommend that you add and maintain a `CITATION.cff` file for your lesson, in [Citation File Format](https://citation-file-format.github.io/) (CFF). CFF is a structured text file format that provides machine-readable citation information for projects. It is supported by a growing number of tools, including GitHub: if a project includes a CFF file in its default branch, [GitHub will present citation information for the project](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files) under a _'Cite this repository'_ button in the _About_ sidebar.
+
+### Creating a CFF for a lesson
+
+You can use the [`cffinit` webtool](https://citation-file-format.github.io/cff-initializer-javascript/) to create a new CFF for your lesson or update an existing file.
+When creating a CFF for a lesson, you should specify `dataset` as the type of work being described ([This discussion includes explanation for why `dataset` is the appropriate type for a lesson](https://github.com/carpentries/sandpaper/issues/508#issuecomment-1699302887).)
+
+::::::::::::::::::::::::::::::::::::::::: spoiler
+
+### Example CFF for this lesson
+
+```
+cff-version: 1.2.0
+title: Introduction to The Carpentries Workbench
+message: >-
+ Please cite this lesson using the information in this file
+ when you refer to it in publications, and/or if you
+ re-use, adapt, or expand on the content in your own
+ training material. To cite the Workbench software itself,
+ please refer to the websites for the individual
+ components:
+ https://carpentries.github.io/sandpaper/authors.html#citation,
+ https://carpentries.github.io/pegboard/authors.html#citation,
+ https://carpentries.github.io/varnish/authors.html#citation
+type: dataset
+authors:
+ - given-names: Zhian
+ family-names: Kamvar
+ name-particle: N.
+ orcid: 'https://orcid.org/0000-0003-1458-7108'
+ - given-names: Toby
+ family-names: Hodges
+ email: tobyhodges@carpentries.org
+ affiliation: The Carpentries
+ orcid: 'https://orcid.org/0000-0003-1766-456X'
+ - given-names: Erin
+ family-names: Becker
+ orcid: 'https://orcid.org/0000-0002-6832-0233'
+ - orcid: 'https://orcid.org/0000-0002-7040-548X'
+ given-names: Sarah
+ family-names: Stevens
+ - given-names: Michael
+ family-names: Culshaw-Maurer
+ orcid: 'https://orcid.org/0000-0003-2205-8679'
+ - given-names: Maneesha
+ family-names: Sane
+ - given-names: Robert
+ family-names: Davey
+ orcid: 'https://orcid.org/0000-0002-5589-7754'
+ - given-names: Amelia
+ family-names: Bertozzi-Villa
+ - given-names: Kaitlin
+ family-names: Newson
+ orcid: 'https://orcid.org/0000-0001-8739-5823'
+ - given-names: Jennifer
+ family-names: Stubbs
+ orcid: 'https://orcid.org/0000-0002-6080-5703'
+ - given-names: Belinda
+ family-names: Weaver
+ - given-names: François
+ family-names: Michonneau
+ orcid: 'https://orcid.org/0000-0002-9092-966X'
+repository-code: 'https://github.com/carpentries/sandpaper-docs'
+url: 'https://carpentries.github.io/sandpaper-docs/'
+abstract: >-
+ Documentation for The Carpentries Workbench, a set of
+ tools that can be used to create accessible lesson
+ websites.
+keywords:
+ - Carpentries
+ - sandpaper
+ - pegboard
+ - varnish
+ - R
+ - pkgdown
+license: CC-BY-4.0
+```
+
+:::::::::::::::::::::::::::::::::::::::::::::::::
+
+### Plain text CITATION file
+
+As an alternative to Citation File Format, you can also use a plain text file, named `CITATION` (i.e. without the `.cff` extension), in which you add guidance for people wanting to cite your lesson in their publications/projects.
+
+::::::::::::::::::::::::::::::::::::::::: spoiler
+
+### Example plain text CITATION file
+
+```
+Please cite this lesson as:
+
+Zhian N. Kamvar et al,
+Introduction to The Carpentries Workbench.
+https://github.com/carpentries/sandpaper-docs
+```
+
+:::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+::::::::::::::::::::: keypoints
+
+- `sandpaper::build_lesson()` renders the site and rebuilds any sources that have changed.
+- RStudio shortcuts are cmd + shift + B and cmd + shift + K
+- To edit a lesson, you only need to know Markdown and/or R Markdown
+- The folder structure is designed with maintainers in mind
+- New episodes can be added with `sandpaper::create_episode()`
+
+:::::::::::::::::::::::::::::::
+
+[pandoc]: https://pandoc.org/
diff --git a/episodes.md b/episodes.md
new file mode 100644
index 00000000..f913a2c9
--- /dev/null
+++ b/episodes.md
@@ -0,0 +1,1107 @@
+---
+title: "Episode Structure"
+teaching: 15
+exercises: 2
+---
+
+
+
+:::::::::::::::::::::::::::::::::::::: questions
+
+- How do you create a new episode?
+- What syntax do you need to know to contribute to a lesson with The Carpentries Workbench?
+- How do you write challenge blocks?
+- What syntax do you use to write links?
+- How do you include images?
+- How do you include math?
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::::::::::: objectives
+
+- Practise creating a new episode with R
+- Understand the required elements for each episode
+- Understand pandoc-flavored markdown
+- Demonstrate how to include pieces of code, figures, and nested challenge blocks
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+## Introduction
+
+An episode[^episodes] is an individual unit of a lesson that focuses on a
+single topic with clear questions, objectives, and key points. If a lesson goal
+is to teach you about using git, an individual episode would teach you how to
+inspect the status of a git repsitory. The idea behind the name "episode" is
+the thought that each one should last about as long as an episode for an
+television series.
+
+As we will cover in the [next episode](editing.md), all of the episodes live
+inside the `episodes/` directory at the top of the lesson folder. Their order is
+dictated by the `episodes:` element in the `config.yaml` file (but defaults to
+alphabetical). The other folders (`learners/`, `instructors/`, and `profiles/`)
+are similarly configured. This episode will briefly explain how to edit markdown
+content in the lessons.
+
+
+:::::: prereq
+
+### Buoyant Barnacle
+
+The exercises in this episode correspond to the Buoyant Barnacle repository you
+created in [the Introduction](introduction.md)
+
+:::::::::::::
+
+There are three things you should be comfortable with in order to contribute to
+a lesson [^worry]
+
+1. Writing [basic][basic-syntax] and [extended][extended-syntax] markdown syntax
+2. Writing [Fenced div elements][fenced-divs] to create callouts and exercise
+ blocks
+2. Writing simple yaml lists
+
+## Creating A New Episode
+
+To create a new episode, you should open your lesson (`buoyant-barnacle`) in
+your RStudio or your favorite text editor and in the R console type:
+
+```r
+sandpaper::create_episode("next-episode")
+```
+
+This will create a new episode in the episodes folder called
+"02-next-episode.Rmd". If you already have your episode schedule set in
+`config.yaml`, then this episode will not be rendered in the site and will
+remain a draft until you add it to the schedule. Next, we will show how you can
+add a title and other elements to your episode.
+
+:::::::::::::::::::::::::::::::: callout
+
+### What is the `.Rmd` extension?
+
+You might notice that the new episode has the extension of `.Rmd` instead of
+`.md`. This is R Markdown, an extension of markdown that allows us to insert
+special code fences that can execute R code and automatically produce output
+chunks with controls of how the output and input are rendered in the document.
+
+For example, this markdown code fence will not produce any output, but it is
+valid for both Markdown and R Markdown.
+
+````markdown
+```r
+print("hello world!")
+```
+````
+
+```r
+print("hello world!")
+```
+
+But when I open the fence with ```` ```{r} ```` then it becomes an R Markdown
+code fence and will execute the code inside the fence:
+
+
+```` markdown
+```{r}
+print("hello world!")
+```
+````
+
+
+``` r
+print("hello world!")
+```
+
+``` output
+[1] "hello world!"
+```
+
+Note that it is completely optional to use these special code fences!
+
+:::::::::::::::::::::::::::::::::::::::::
+
+## Required Elements
+
+To keep with our active learning principles, we want to be mindful about the
+content we present to the learners. We need to give them a clear title,
+questions and objectives, and an estimate of how long it will take to navigate
+the episode (though this latter point has shown to be demoralizing). Finally, at
+the end of the episode, we should reinforce the learners' progress with a summary
+of key points.
+
+### YAML metadata
+
+The YAML syntax of an episode contains three elements of metadata associated
+with the episode at the very top of the file:
+
+```yaml
+---
+title: "Using RMarkdown For Automated Reports" # Episode title
+teaching: 5 # teaching time in minutes
+exercises: 10 # exercise time in minutes
+---
+
+## First Episode Section
+```
+
+:::::::::::::::: challenge
+
+### Create a Title
+
+Your new episode needs a title!
+
+1. Open the new episode in your editor
+2. edit the title
+3. add the episode to the `config.yaml`
+4. preview it with `sandpaper::build_lesson()` or using the ctrl + shift + k keyboard shortcut.
+
+Did the new title show up?
+
+::::::::::::::::::::::::::
+
+### Questions, Objectives, Keypoints
+
+These are three blocks that live at the top and bottom of the episodes.
+
+1. `questions` are displayed at the beginning of the episode to prime the
+learner for the content
+2. `objectives` are the learning objectives for an episode and are
+displayed along with the questions
+3. `keypoints` are displayed at the end of the episode to reinforce the
+objectives
+
+They are formatted as [pandoc fenced divisions][fenced-divs], which we will
+explain in [the next section](#callout-blocks):
+
+```markdown
+---
+title:
+teaching:
+exercises:
+---
+
+:::::: questions
+ - question 1
+ - question 2
+::::::
+
+:::::: objectives
+ - objective 1
+ - objective 2
+::::::
+
+
+
+:::::: keypoints
+ - keypoint 1
+ - keypoint 2
+::::::
+```
+
+
+## Optional Elements
+
+Lessons do not have to contain the following structural elements, but
+they can be useful for highlighting particular content.
+
+### Callout blocks {#callout-blocks}
+
+
+One of the key elements of our lessons are our callout blocks that give learners
+and instructors a **bold visual cue** to stop and consider a caveat or exercise.
+To create these blocks, we use [**pandoc fenced divisions, aka
+_'fenced-divs'_**][fenced-divs], which are colon-delimited sections similar to
+code fences that can instruct the markdown interpreter how the content should be
+styled.
+
+
+::::: callout
+
+### Callout Component Guide
+
+You can find a catalogue of the different callout blocks The Workbench supports
+in [The Workbench Component Guide](component-guide.md).
+
+::::::::::::
+
+
+For example, to create a `callout` block, we would use *a blank line and at least three colons*
+followed by the `callout` tag (the tag designates an open fence), add our
+content after a new line, and then close the fence with *at least three colons*
+and no tag (which designates a closed fence):
+
+```markdown
+::: callout
+This is a callout block. It contains at least three colons
+:::
+```
+
+::: callout
+This is a callout block. It contains at least three colons
+:::
+
+However, it may be difficult sometimes to keep track of a section if it's only
+delimited by three colons. Because [the specification for fenced-divs require
+*at least* three colons][fenced-divs], it's possible to include more to really
+differentiate between these and headers or code fences:
+
+```markdown
+::::::::::::::::::::::::::::::::::::::::::::::: testimonial
+
+I'm **really excited** for the _new template_ when it arrives :grin:.
+
+--- Toby Hodges
+
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+```
+
+::::::::::::::::::::::::::::::::::::::::::::::: testimonial
+I'm **really excited** for the _new template_ when it arrives :grin:.
+
+--- Toby Hodges
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+Even better, you do not have to worry about counting colons! It doesn't matter
+how many colons you put for the opening and closing fences, all that matters is
+you can visually see that the fences match.
+
+::::::::::::::::::::::::::::::::::::::::::::::: callout
+
+That's right, we can use emojis in The Carpentries Workbench! :100: :tada:
+
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+### Tabbed content {#tabbed-content}
+
+Available from varnish v1.0.2, tabs are a great way to present multiple pieces
+of information in a compact and organised way. You can create them in two ways:
+firstly with a `tab` fenced div, and secondly with a `group-tab` fenced div.
+
+Whilst they both show content in the same way, grouped tabs differ from standard tabs
+in that they remember which tab you have selected across page changes. This can be
+useful if you want to use a specific tab throughout the lesson content,
+e.g. for a set of exercises or a set of solutions you want to use the "Windows" tab
+that was initially selected in the Setup episode.
+
+The first tab specified is the default tab.
+
+In both cases, tabs can hold callouts themselves and be specified within callouts
+too!
+
+#### Tab
+
+To create a tab group, create a `tab` fenced div, and
+then add a level 3 markdown heading (`###`) for each tab you want to create:
+
+````markdown
+::: tab
+
+### Windows
+
+Some Windows instructions
+
+### Mac
+
+Maybe some for Mac
+
+### Linux
+
+And more for Linux users, including a code block:
+
+```python
+ print("Yay, tabs!")
+```
+
+:::
+````
+
+::: tab
+
+### Windows
+
+Some Windows instructions
+
+### Mac
+
+Maybe some for Mac
+
+### Linux
+
+And more for Linux users, including a code block:
+
+```python
+ print("Yay, tabs!")
+```
+
+:::
+
+
+#### Grouped tabs
+
+Much like standard `tab`s, to create grouped tabs use a `group-tab` fenced div, and
+then add a level 3 markdown heading (`###`) for each tab you want to create:
+
+
+```markdown
+::: group-tab
+
+### Windows
+
+1
+
+### Mac
+
+2
+
+### Linux
+
+3
+
+:::
+
+::: group-tab
+
+### Windows
+
+4
+
+### Mac
+
+5
+
+### Linux
+
+6
+
+:::
+```
+
+The first tab specified is the default tab.
+
+In the example below, selecting a tab in one tab group changes the tab in
+the other group(s).
+
+::: group-tab
+
+### Windows
+
+1
+
+### Mac
+
+2
+
+### Linux
+
+3
+
+:::
+
+::: group-tab
+
+### Windows
+
+4
+
+### Mac
+
+5
+
+### Linux
+
+6
+
+:::
+
+(Thanks to [@astroDimitrios](https://github.com/astroDimitrios) for this great feature!)
+
+## Instructor Notes
+
+The Carpentries Workbench supports separate instructor/learner views,
+which allows for instructor notes to be incorporated into the lesson. The
+default view of a lesson is the learner view, but you can switch to the
+instructor view by scrolling to the top of the lesson, clicking on the "Learner
+View" button at the top right, and then selecting "Instructor View" from the
+dropdown. You can also add `instructor/` after the lesson URL (e.g. in this
+lesson, the URL is `https://carpentries.github.io/sandpaper-docs/episodes.html`;
+to switch to the instructor view manually, you can use
+`https://carpentries.github.io/sandpaper-docs/instructor/episodes.html`).
+
+
+::::::::::::::: challenge
+
+### View the instructor note
+
+When you visit this page, the default is learner view. Scroll to the top of the
+page and select "Instructor View" from the dropdown and return to this section
+to find an instructor note waiting for you.
+
+:::::::::::::::::::::::::::
+
+````markdown
+
+::::::::::::::::::::::::::::::::::::: instructor
+
+This is an instructor note. It contains information that can be useful for
+instructors to know such as
+
+ - **Useful hints** about places that need extra attention
+ - **setup instructions** for live coding
+ - **reminders** of what the learners should already know
+ - anything else
+
+```markdown
+You can also include _any markdown elements_ like `code blocks`
+```
+
+![Images can also appear in instructor notes](https://placekitten.com/200/200){alt='a random image of a cute kitten'}
+
+:::::::::::::::::::::::::::::::::::::::::::::::::
+
+````
+
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: instructor
+
+This is an instructor note. It contains information that can be useful for
+instructors to know such as
+
+ - **Useful hints** about places that need extra attention
+ - **setup instructions** for live coding
+ - **reminders** of what the learners should already know
+ - anything else
+
+```markdown
+You can also include _any markdown elements_ like `code blocks`
+```
+
+![Images can also appear in instructor notes](https://placekitten.com/200/200){alt='a random image of a cute kitten'}
+
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+## Exercises/Challenges
+
+The method of creating callout blocks with fences can help us create solution
+blocks nested within challenge blocks. Much like a [toast
+sandwich](https://en.wikipedia.org/wiki/Toast_sandwich), we can layer blocks
+inside blocks by adding more layers. For example, here's how I would create a
+single challenge and a single solution:
+
+```markdown
+::::::::::::::::::::::::::::::::::::: challenge
+
+## Chemistry Joke
+
+Q: If you aren't part of the solution, then what are you?
+
+:::::::::::::::: solution
+
+A: part of the precipitate
+
+:::::::::::::::::::::::::
+:::::::::::::::::::::::::::::::::::::::::::::::
+```
+
+::::::::::::::::::::::::::::::::::::: challenge
+
+## Chemistry Joke
+
+Q: If you aren't part of the solution, then what are you?
+
+:::::::::::::::: solution
+
+A: part of the precipitate
+
+:::::::::::::::::::::::::
+:::::::::::::::::::::::::::::::::::::::::::::::
+
+To add more content to the challenge, you close the first solution and add more text:
+
+::::::::::::::::::::::::::::::::::::: challenge
+
+## Challenge 1: Can you do it?
+
+What is the output of this command?
+
+
+``` r
+paste("This", "new", "template", "looks", "good")
+```
+
+:::::::::::::::::::::::: solution
+
+## Output
+
+
+``` output
+[1] "This new template looks good"
+```
+
+:::::::::::::::::::::::::::::::::
+
+
+## Challenge 2: how do you nest solutions within challenge blocks?
+
+:::::::::::::::::::::::: solution
+
+You can add a line with at least three colons and a `solution` tag.
+
+:::::::::::::::::::::::::::::::::
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+Now, here's a real challenge for you
+
+:::::::::::::::::::::::::::::::::::::: challenge
+
+Is the following fenced-div valid? Why?
+
+```markdown
+::::::::::::::::::::: my-class
+This is a block of my class
+:::
+```
+
+::::::::::::::::::::::: solution
+
+Yes! It is a valid fenced div for the following reasons:
+
+1. The opening fence has ≥3 colons
+2. The opening fence has a class designation
+3. The closing fence is on its own line and has ≥3 colons
+
+:::::::::::::::::::::::::::::::::
+
+:::::::::::::::::::::::::::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::::::::::::::::::::: callout
+
+## Use Spoilers Instead of Floating Solution Blocks
+
+When not attached to a `challenge` div, a formatted `solution` block
+will be displayed with too much "buoyancy"
+i.e. floating too high and obscuring some of the preceding content.
+
+To avoid this, use the `spoiler` class of fenced div
+for expandable/collapsible blocks of details
+instead of a floating `solution`.
+
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+## Expandable "Spoiler" Blocks
+
+It can be helpful to provide "accordion" blocks of content
+that can be expanded and collapsed with a mouse click
+in some circumstances e.g.
+to provide detailed instructions for different operating systems,
+which can be examined by users based on their own system setup.
+
+Such blocks of content can be added to a page with the `spoiler` class of fenced div:
+
+```markdown
+:::::::::::::::::::::::::::::::::::::::::: spoiler
+
+### What Else Might We Use A Spoiler For?
+
+- including a collapsed version of a very long block of output/a large image from a code block,
+ which the learner can expand if they want to check their output against the lesson
+- a reminder of some important concept/information required to follow the lesson,
+ that you expect only some learners will need to read
+- wrapping a set of optional exercises for an episode
+
+::::::::::::::::::::::::::::::::::::::::::::::::::
+```
+
+:::::::::::::::::::::::::::::::::::::::::: spoiler
+
+### What Else Might We Use A Spoiler For?
+
+- including a collapsed version of a very long block of output/a large image from a code block,
+ which the learner can expand if they want to check their output against the lesson
+- a reminder of some important concept/information required to follow the lesson,
+ that you expect only some learners will need to read
+- wrapping a set of optional exercises for an episode
+
+::::::::::::::::::::::::::::::::::::::::::::::::::
+
+## Code Blocks with Syntax Highlighting
+
+To include code examples in your lesson, you can wrap it in three backticks like
+so:
+
+Input:
+
+````markdown
+```
+thing = "python"
+print("this is a {} code block".format(thing))
+```
+````
+Output:
+
+```
+thing = "python"
+print("this is a {} code block".format(thing))
+```
+
+To include a label and syntax highlighting, you can add a label after the first
+set of backticks:
+
+Input:
+
+````markdown
+```python
+thing = "python"
+print("this is a {} code block".format(thing))
+```
+````
+Output:
+
+```python
+thing = "python"
+print("this is a {} code block".format(thing))
+```
+
+To indicate that a code block is an output block, you can use the label "output":
+
+Input:
+
+````markdown
+```python
+thing = "python"
+print("this is a {} code block".format(thing))
+```
+
+```output
+this is a python code block
+```
+
+````
+Output:
+
+```python
+thing = "python"
+print("this is a {} code block".format(thing))
+```
+
+```output
+this is a python code block
+```
+
+The number of available languages for syntax highlighting are numerous and
+chances are, if you want to highlight a particular language, you can add the
+language name as a label and it will work. A [full list of supported languages
+is here, each language being a separate XML file definition](https://github.com/jgm/skylighting/tree/master/skylighting-core/xml).
+
+## Tables
+
+Tables in The Workbench follow the rules for [pandoc pipe table
+syntax][pipe-table-syntax], which is the most portable form of tables.
+
+Because we use pandoc for rendering, tables also have the following features:
+
+1. You can add a table caption, which is great for accessibility[^tablecap]
+2. You have control over the relative width of oversized table contents
+
+Here is an example of a narrow table with three columns aligned left, center,
+and right, respectively.
+
+[pipe-table-syntax]: https://pandoc.org/MANUAL.html#extension-pipe_tables
+
+```markdown
+Table: Four fruits with color and price in imaginary dollars
+
+| fruit | color | price |
+| ------ | :--------------: | -------: |
+| apple | :red_circle: | \$2.05 |
+| pear | :green_circle: | \$1.37 |
+| orange | :orange_circle: | \$3.09 |
+| gum gum fruit | :purple_circle: | \$999.99 |
+```
+
+Table: Four fruits with color and price in imaginary dollars
+
+| fruit | color | price |
+| ------ | :--------------: | -------: |
+| apple | :red_circle: | \$2.05 |
+| pear | :green_circle: | \$1.37 |
+| orange | :orange_circle: | \$3.09 |
+| gum gum fruit | :purple_circle: | \$999.99 |
+
+You can see that we now have a caption associated with the table.
+
+:::::::::::::: callout
+
+### Table alignment best practises
+
+The colons on each side of the `-` in the table dictate how the column is
+aligned. By default, columns are aligned left, but if you add colons on either
+side, that forces the alignment to that side.
+
+In general, most table contents should be left-aligned, with a couple of
+exceptions:
+
+ - numbers should be right aligned
+ - symbols, emojis, and other equal-width items may be center-aligned
+
+These conventions make it easer for folks to scan a table and understand its
+contents at a glance.
+
+::::::::::::::::::::::
+
+Because it is a narrow table, the columns fit exactly to the contents. If we
+added a fourth, longer column (e.g. a description), then the table looks a bit
+wonky:
+
+```markdown
+Table: Four fruits with color, price in imaginary dollars, and description
+
+| fruit | color | price | description |
+| ------ | :--------------: | -------: | ----------- |
+| apple | :red_circle: | \$2.05 | a short, round-ish red fruit that is slightly tapered at one end. It tastes sweet and crisp like a fall day |
+| pear | :green_circle: | \$1.37 | a bell-shaped green fruit whose taste is sweet and mealy like a cold winter afternoon |
+| orange | :orange_circle: | \$3.09 | a round orange fruit with a dimply skin-like peel that you must remove before eating. It tastes of sweet and sour lazy summer days |
+| gum gum fruit | :purple_circle: | \$999.99 | a round purple fruit with complex swirls along its skin. It is said to taste terrible and give you mysterious powers |
+```
+
+Table: Four fruits with color and price in imaginary dollars
+
+| fruit | color | price | description |
+| ------ | :--------------: | -------: | ----------- |
+| apple | :red_circle: | \$2.05 | a short, round-ish red fruit that is slightly tapered at one end. It tastes sweet and crisp like a fall day |
+| pear | :green_circle: | \$1.37 | a bell-shaped green fruit whose taste is sweet and mealy like a cold winter afternoon |
+| orange | :orange_circle: | \$3.09 | a round orange fruit with a dimply skin-like peel that you must remove before eating. It tastes of sweet and sour lazy summer days |
+| gum gum fruit | :purple_circle: | \$999.99 | a round purple fruit with complex swirls along its skin. It is said to taste terrible and give you mysterious powers |
+
+
+If we want to adjust the size of the columns, we need to change the lengths of
+the number of dashes separating the header from the body (as described in
+[pandoc's guide for tables][pipe-table-syntax]).
+
+Notice how the pipe characters (`|`) do not necessarily have to line up to
+produce a table.
+
+
+``` markdown
+Table: Four fruits with color, price in imaginary dollars, and description
+
+| fruit | color | price | description |
+| ---- | :-: | ---: | --------------------------- |
+| apple | :red_circle: | \$2.05 | a short, round-ish red fruit that is slightly tapered at one end. It tastes sweet and crisp like a fall day |
+| pear | :green_circle: | \$1.37 | a bell-shaped green fruit whose taste is sweet and mealy like a cold winter afternoon |
+| orange | :orange_circle: | \$3.09 | a round orange fruit with a dimply skin-like peel that you must remove before eating. It tastes of sweet and sour lazy summer days |
+| gum gum fruit | :purple_circle: | \$999.99 | a round purple fruit with complex swirls along its skin. It is said to taste terrible and give you mysterious powers |
+```
+
+Table: Four fruits with color, price in imaginary dollars, and description
+
+| fruit | color | price | description |
+| ---- | :-: | ---: | --------------------------- |
+| apple | :red_circle: | \$2.05 | a short, round-ish red fruit that is slightly tapered at one end. It tastes sweet and crisp like a fall day |
+| pear | :green_circle: | \$1.37 | a bell-shaped green fruit whose taste is sweet and mealy like a cold winter afternoon |
+| orange | :orange_circle: | \$3.09 | a round orange fruit with a dimply skin-like peel that you must remove before eating. It tastes of sweet and sour lazy summer days |
+| gum gum fruit | :purple_circle: | \$999.99 | a round purple fruit with complex swirls along its skin. It is said to taste terrible and give you mysterious powers |
+
+:::::::::::::::::::::::::::: challenge
+
+### Adjust column widths
+
+Adjust the widths of the columns below so that the columns are around a 1:5:1
+ratio with the second column having center-justification:
+
+```markdown
+Table: example table with overflowing text in three columns
+
+| first | second | third |
+| ----- | ------ | ----- |
+| this should be a small, compact column | this should be a wide column | this column should also be small and compact, much like the first column |
+```
+
+Table: example table with overflowing text in three columns
+
+| first | second | third |
+| ----- | ------ | ----- |
+| this should be a small, compact column | this should be a wide column | this column should also be small and compact, much like the first column |
+
+:::::::::::::: solution
+
+To get a roughly 1:5:1 ratio, you can use two separators for the short columns
+and ten separators for the wide column:
+
+```markdown
+Table: example table with overflowing text in three columns
+
+| first | second | third |
+| -- | :--------: | -- |
+| this should be a small, compact column | this should be a wide column | this column should also be small and compact, much like the first column |
+```
+
+Table: example table with overflowing text in three columns
+
+| first | second | third |
+| -- | :--------: | -- |
+| this should be a small, compact column | this should be a wide column | this column should also be small and compact, much like the first column |
+
+
+::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::::::::::::
+
+
+### R Markdown tables
+
+If you are using R Markdown, then you can generate a table from packages like
+{knitr} or {gt}, but make sure to use `results = 'asis'` in your chunk option:
+
+
+```` markdown
+
+```{r fruits-table, results = 'asis'}
+dat <- data.frame(
+ stringsAsFactors = FALSE,
+ fruit = c("apple", "pear", "orange", "gum gum fruit"),
+ color = c("π΄", "π’", "π ", "π£"),
+ price = c("$2.05", "$1.37", "$3.09", "$999.99"),
+ description = c("a short, round-ish red fruit that is slightly tapered at one end. It tastes sweet and crisp like a fall day",
+ "a bell-shaped green fruit whose taste is sweet and mealy like a cold winter afternoon",
+ "a round orange fruit with a dimply skin-like peel that you must remove before eating. It tastes of sweet and sour lazy summer days",
+ "a round purple fruit with complex swirls along its skin. It is said to taste terrible and give you mysterious powers")
+)
+knitr::kable(dat,
+ format = "pipe",
+ align = "lcrl",
+ caption = "Four fruits with color, price in imaginary dollars, and description")
+```
+````
+
+
+Table: Four fruits with color, price in imaginary dollars, and description
+
+|fruit | color | price|description |
+|:-------------|:-----:|-------:|:----------------------------------------------------------------------------------------------------------------------------------|
+|apple | π΄ | $2.05|a short, round-ish red fruit that is slightly tapered at one end. It tastes sweet and crisp like a fall day |
+|pear | π’ | $1.37|a bell-shaped green fruit whose taste is sweet and mealy like a cold winter afternoon |
+|orange | π | $3.09|a round orange fruit with a dimply skin-like peel that you must remove before eating. It tastes of sweet and sour lazy summer days |
+|gum gum fruit | π£ | $999.99|a round purple fruit with complex swirls along its skin. It is said to taste terrible and give you mysterious powers |
+
+
+
+[^tablecap]: Captions allow visually impaired users to choose if they want to skip over the table contents if it is scannable. For more information, you can read
+[MDN docs: adding a caption to your table](https://developer.mozilla.org/en-US/docs/Learn/HTML/Tables/Advanced#adding_a_caption_to_your_table_with_caption)
+
+## Links
+
+To include links to outside resources in your lesson, you write them with [standard
+markdown syntax][basic-syntax]: `[descriptive link text](https://example.com/link-url)`.
+One thing to remember when writing links (in markdown or anywhere) is that
+[link text should make sense out of context](https://webaim.org/techniques/hypertext/link_text#uninformative).
+If you find that the link URL you are using is long, or you want to reuse it multiple times, you can use
+a link anchor with the following syntax:
+
+```markdown
+This is an example of a [link reference].
+
+I have a long sentence that also has [a link with a long url][long-url-link], so I will use a link reference.
+
+
+[link reference]: https://example.com/link-reference
+[long-url-link]: https://example.com/long-url-is-loooooooooooooooooooooooooong
+```
+
+If you have a link that you want to use across your lesson (e.g. you have a source for a data set that you
+want to refer to), then you can place a link inside a separate file at the top of your lesson repository called `links.md`.
+
+### Internal Links
+
+When working on a lesson in The Workbench, you do not need to think about what
+link the website will generate once it's built in order to write a link to
+different elements in the lesson. This is important because when you write
+links relative to your source files, these links will be predictable in any
+context and allow you to easily detect when filenames change.
+
+To reference other markdown files within the same lesson, use _relative paths
+from the current file_. For example, you will commonly want to refer learners
+to [the setup page](../learners/setup.md) from within the episodes. To link
+back to the setup page, you can use: `[setup page](../learners/setup.md)` and
+{sandpaper} will convert that link to the appropriate format for the lesson
+website.
+
+
+By that same rule, here is how you would write the following links in this episode:
+
+
+```markdown
+ - [another episode (e.g. introduction)](introduction.md)
+ - [the home page](../index.md)
+ - [the setup page](../learners/setup.md)
+ - [the "line length" section in the style guide](../learners/style.md#line-length)
+```
+
+ - [another episode (e.g. introduction)](introduction.md)
+ - [the home page](../index.md)
+ - [the setup page](../learners/setup.md)
+ - [the "line length" section in the style guide](../learners/style.md#line-length)
+
+:::::::::::::::::::::::::::::::::: challenge
+
+#### But It Works!
+
+You want to create a link **from [the style guide](../learners/style.md) in the
+learners folder** to _this section_ on links. All of the links below _will_
+work with The Carpentries Workbench, but which one is _guaranteed_ to work and
+why?
+
+ 1. `[internal links](https://carpentries.github.io/sandpaper-docs/episodes.html#internal-links)`
+ 2. `[internal links](episodes.html#internal-links)`
+ 3. `[internal links](../episodes/episodes.Rmd#internal-links)`
+ 4. `[internal links](../episodes/episodes.md#internal-links)`
+ 5. `[internal links](episodes#internal-links)`
+
+:::::::::::::: hint
+
+Think about which files _actually_ exist before the lesson is built.
+
+:::::::::::::::::::::::
+:::::::::::::: solution
+
+The answer is **3**:
+`[internal links](../episodes/episodes.Rmd#internal-links)`
+produces [internal links](../episodes/episodes.Rmd#internal-links)
+
+##### incorrect solutions
+
+The reasons the others were incorrect is:
+
+1. this produces a full static URL, but the URL could easily change (for
+ example, when there is a translation or a fork of this lesson).
+2. this produces a relative link to the URL, but this can change if
+ the folder structure of the rendered website changes
+ (e.g. it becomes `episodes/index.html`).
+3. this is the correct choice, see above.
+4. the file extension is incorrect. _This episode_ is written in R Markdown
+ and needs the `Rmd` file extension.
+5. this is ambiguous, but it is similar to number 2, where it's providing a
+ relative link to a URL. This _only_ works on GitHub, where the `.html`
+ extension is optional.
+
+
+:::::::::::::::::::::::
+
+:::::::::::::::::::::::::::::::::::::::::::::
+
+## Figures
+
+To include figures, place them in the `episodes/fig` folder and reference them
+directly like so using standard markdown format, with one twist: add an `alt`
+attribute at the end to make it accessible like this:
+`![caption](image){alt='alt text'}`.
+
+```markdown
+![Hex sticker for The Carpentries](fig/carpentries-hex-blue.svg){alt="blue
+hexagon with The Carpentries logo in white and text: 'The Carpentries'"}
+```
+
+![Hex sticker for The Carpentries](fig/carpentries-hex-blue.svg){alt="blue
+hexagon with
+The Carpentries logo in white and text:
+'The Carpentries'"}
+
+
+:::::::::::::::::::::::::::: discussion
+
+### Accessibility Point: Alternative Text (aka alt-text)
+
+Alternative text (alt text) is a very important tool for making lessons
+accessible. If you are unfamiliar with alt text for images, [this primer on alt
+text gives a good rundown of what alt text is and why it matters][alt-text]. In
+short, alt text provides a short description of an image that can take the place
+of an image if it is missing or the user is unable to see it.
+
+#### How long should alt text be?
+
+Alt text is a wonderful accessibility tool that gives a description of an image
+when it can not be perceived visually. As the saying goes, a picture is worth a
+thousand words, but alt text likely should not be so long, so how long should it
+be? That depends on the context. Generally, if a figure is of minor importance,
+then try to constrain it to about the length of a tweet (~150-280 characters) or
+it will get _too_ descriptive, otherwise, describe the salient points that the
+reader should understand from the figure.
+
+#### Wrapping Alt Text lines
+
+You will rarely have alt text that fits under 100 characters, so you can wrap
+alt text like you would any markdown paragraph:
+
+```markdown
+![Example of Wrapped Alt Text (with apologies to William Carlos Williams)](fig/freezer.png){alt='This is just an icebox
+with no plums
+which you were probably
+saving
+for breakfast'}
+```
+
+When missing, the image will appear visually as a broken image icon, but the alt
+text describes what the image was.
+
+![Example of Wrapped Alt Text (with apologies to William Carlos Williams)](fig/freezer.png){alt='This is just an icebox
+with no plums
+which you were probably
+saving
+for breakfast'}
+
+#### Decorative Images
+
+If you have a decorative image such as logo that is not important for the
+content of the lesson, then you should use `alt=""` to mark it as decorative so
+that screen readers will know to skip that image.
+
+::::::::::::::::::::::::::::::::::::::
+
+If your lesson uses R, some images will be auto-generated from evaluated code
+chunks and linked. You can use `fig.alt` to include alt text. [This blogpost has
+more information about including alt text in RMarkdown
+documents](https://blog.rstudio.com/2021/04/20/knitr-fig-alt/). In addition, you
+can also use `fig.cap` to provide a caption that puts the picture into context
+(but take care to not be redundant; screen readers will read both fields).
+
+
+``` r
+pie(
+ c(Sky = 78, "Sunny side of pyramid" = 17, "Shady side of pyramid" = 5),
+ init.angle = 315,
+ col = c("deepskyblue", "yellow", "yellow3"),
+ border = FALSE
+)
+```
+
+
+
+
Sun arise each and every morning
+
+
+## Math
+
+One of our episodes contains $\LaTeX$ equations when describing how to create
+dynamic reports with {knitr}, so we now use mathjax to describe this:
+
+`$\alpha = \dfrac{1}{(1 - \beta)^2}$` becomes: $\alpha = \dfrac{1}{(1 - \beta)^2}$
+
+Cool, right?
+
+:::::::::::::::: keypoints :::::::::::::::::::::
+
+- Use `.Rmd` files for lessons even if you don't need to generate any code
+- Run `sandpaper::check_lesson()` to identify any issues with your lesson
+- Run `sandpaper::build_lesson()` to preview your lesson locally
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+[alt-text]: https://axesslab.com/alt-texts/
+[^episodes]: The designation of "episode" will likely change. Throught UX
+ testing, it's clear that calling these lesson units "episodes" is confusing,
+ even for people who have been in The Carpentries for several years. The
+ current working proposal is to call these "chapters".
+[^worry]: Do not worry if you aren't comfortable yet, that's what we will show
+ you in this episode!
+
diff --git a/example.md b/example.md
new file mode 100644
index 00000000..864ce97d
--- /dev/null
+++ b/example.md
@@ -0,0 +1,178 @@
+---
+title: "EXAMPLE: Using RMarkdown"
+teaching: 5
+exercises: 2
+---
+
+:::::::::::::::::::::::::::::::::::::: questions
+
+- How do you write a lesson using R Markdown and `{sandpaper}`?
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::::::::::: objectives
+
+- Explain how to use markdown with the new lesson template
+- Demonstrate how to include pieces of code, figures, and nested challenge blocks
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+## Introduction
+
+This is a lesson created via The Carpentries Workbench. It is written in
+[Pandoc-flavored Markdown][pandoc] for static files and
+[R Markdown][r-markdown] for dynamic files that can render code into output.
+Please refer to the [Introduction to The Carpentries
+Workbench][carpentries-workbench] for full documentation.
+
+What you need to know is that there are three sections required for a valid
+Carpentries lesson template:
+
+ 1. `questions` are displayed at the beginning of the episode to prime the
+ learner for the content.
+ 2. `objectives` are the learning objectives for an episode displayed with
+ the questions.
+ 3. `keypoints` are displayed at the end of the episode to reinforce the
+ objectives.
+
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: instructor
+
+Inline instructor notes can help inform instructors of timing challenges
+associated with the lessons. They appear in the "Instructor View"
+
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+### Code fences
+
+Code fences written in standard markdown format will be highlighted, but not
+evaluated:
+
+```bash
+echo '47 + 2' | bc
+echo '47 * 2' | bc
+```
+
+Code fences written using R Markdown chunk notation will be highlighted and
+executed:
+
+
+``` r
+magic <- sprintf("47 plus 2 equals %d\n47 times 2 equals %d", 47 + 2, 47 * 2)
+cat(magic)
+```
+
+``` output
+47 plus 2 equals 49
+47 times 2 equals 94
+```
+
+It's magic!
+
+::::::::::::::::::::::::::::::::::::: challenge
+
+### Challenge 1: Can you do it?
+
+What is the output of this command?
+
+```r
+paste("This", "new", "lesson", "looks", "good")
+```
+
+:::::::::::::::::::::::: solution
+
+### Output
+
+```output
+[1] "This new lesson looks good"
+```
+
+:::::::::::::::::::::::::::::::::
+
+
+### Challenge 2: how do you nest solutions within challenge blocks?
+
+:::::::::::::::::::::::: solution
+
+You can add a line with at least three colons and a `solution` tag.
+
+:::::::::::::::::::::::::::::::::
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+## Figures
+
+You can also include figures generated from R Markdown:
+
+
+``` r
+pie(
+ c(Sky = 78, "Sunny side of pyramid" = 17, "Shady side of pyramid" = 5),
+ init.angle = 315,
+ col = c("deepskyblue", "yellow", "yellow3"),
+ border = FALSE
+)
+```
+
+
+
+
Sun arise each and every morning
+
+
+Or you can use standard markdown for static figures with the following syntax:
+
+`![optional caption that appears below the figure](figure url){alt='alt text for
+accessibility purposes'}`
+
+For example:
+
+`![You belong in The Carpentries!](fig/Badge_Carpentries.svg){alt='Blue Carpentries hex person logo with no text.'}`
+
+![You belong in The Carpentries!](fig/Badge_Carpentries.svg){alt='Blue Carpentries hex person logo with no text.'}
+
+[Additional attributes can be specified for the image](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img#attributes)
+alongside the alternative text description in the `{}`.
+Some, like `width` and `height`, can be specified directly:
+
+`![You belong in The Carpentries!](fig/Badge_Carpentries.svg){alt='Blue Carpentries hex person logo with no text.' width='25%'}`
+
+![You belong in The Carpentries!](fig/Badge_Carpentries.svg){alt='Blue Carpentries hex person logo with no text.' width='25%'}
+
+:::::::::::: callout
+
+## :art: Advanced Image Styling
+
+More complex styling with arbitrary CSS is also possible within the Workbench,
+by providing CSS directives (separated by `;`) to a `style` attribute inside the `{}`.
+
+However, you should be aware that _all styling must be described in this `style` attribute
+if it is present_, i.e. `width` and `height` must be included as CSS directives
+_within the `style` attribute_ when it is used.
+
+For example, to introduce some padding around the resized image:
+
+`![You belong in The Carpentries!](fig/Badge_Carpentries.svg){alt='Blue Carpentries hex person logo with no text.' style='padding:10px; width:25%'}`
+
+![You belong in The Carpentries!](fig/Badge_Carpentries.svg){alt='Blue Carpentries hex person logo with no text.' style='padding:10px; width:25%'}
+
+Note the use of `:` for the key-value pairs of CSS directives defined within `style`.
+
+::::::::::::::::::::
+
+
+## Math
+
+One of our episodes contains $\LaTeX$ equations when describing how to create
+dynamic reports with {knitr}, so we now use mathjax to describe this:
+
+`$\alpha = \dfrac{1}{(1 - \beta)^2}$` becomes: $\alpha = \dfrac{1}{(1 - \beta)^2}$
+
+Cool, right?
+
+::::::::::::::::::::::::::::::::::::: keypoints
+
+- Use `.md` files for episodes when you want static content
+- Use `.Rmd` files for episodes when you need to generate output
+- Run `sandpaper::check_lesson()` to identify any issues with your lesson
+- Run `sandpaper::build_lesson()` to preview your lesson locally
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
diff --git a/fig/Badge_Carpentries.svg b/fig/Badge_Carpentries.svg
new file mode 100644
index 00000000..da70d40e
--- /dev/null
+++ b/fig/Badge_Carpentries.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/fig/carpentries-hex-blue.svg b/fig/carpentries-hex-blue.svg
new file mode 100644
index 00000000..c7632bfa
--- /dev/null
+++ b/fig/carpentries-hex-blue.svg
@@ -0,0 +1,108 @@
+
+
diff --git a/fig/episodes-rendered-pyramid-1.png b/fig/episodes-rendered-pyramid-1.png
new file mode 100644
index 00000000..73615445
Binary files /dev/null and b/fig/episodes-rendered-pyramid-1.png differ
diff --git a/fig/example-rendered-pyramid-1.png b/fig/example-rendered-pyramid-1.png
new file mode 100644
index 00000000..73615445
Binary files /dev/null and b/fig/example-rendered-pyramid-1.png differ
diff --git a/fig/fork-dialogue.png b/fig/fork-dialogue.png
new file mode 100644
index 00000000..e673ecec
Binary files /dev/null and b/fig/fork-dialogue.png differ
diff --git a/fig/github-pages-gh-pages.png b/fig/github-pages-gh-pages.png
new file mode 100644
index 00000000..66727f2a
Binary files /dev/null and b/fig/github-pages-gh-pages.png differ
diff --git a/fig/github-pages-none.png b/fig/github-pages-none.png
new file mode 100644
index 00000000..39df5463
Binary files /dev/null and b/fig/github-pages-none.png differ
diff --git a/fig/intro-template-screen.png b/fig/intro-template-screen.png
new file mode 100644
index 00000000..782e9515
Binary files /dev/null and b/fig/intro-template-screen.png differ
diff --git a/fig/pr-apprentice-cache.png b/fig/pr-apprentice-cache.png
new file mode 100644
index 00000000..891b7ed2
Binary files /dev/null and b/fig/pr-apprentice-cache.png differ
diff --git a/fig/pr-apprentice-workflow.png b/fig/pr-apprentice-workflow.png
new file mode 100644
index 00000000..e9e957ec
Binary files /dev/null and b/fig/pr-apprentice-workflow.png differ
diff --git a/fig/pr-bot-comment-danger.png b/fig/pr-bot-comment-danger.png
new file mode 100644
index 00000000..379ff344
Binary files /dev/null and b/fig/pr-bot-comment-danger.png differ
diff --git a/fig/pr-bot-comment-ok-new.png b/fig/pr-bot-comment-ok-new.png
new file mode 100644
index 00000000..3d4e9db1
Binary files /dev/null and b/fig/pr-bot-comment-ok-new.png differ
diff --git a/fig/pr-bot-comment-ok.png b/fig/pr-bot-comment-ok.png
new file mode 100644
index 00000000..93161868
Binary files /dev/null and b/fig/pr-bot-comment-ok.png differ
diff --git a/fig/pr-bot-comment-warn.png b/fig/pr-bot-comment-warn.png
new file mode 100644
index 00000000..9e82d8c2
Binary files /dev/null and b/fig/pr-bot-comment-warn.png differ
diff --git a/fig/pr-bot-comment.png b/fig/pr-bot-comment.png
new file mode 100644
index 00000000..bb83cde5
Binary files /dev/null and b/fig/pr-bot-comment.png differ
diff --git a/fig/pr-bot-workflow.png b/fig/pr-bot-workflow.png
new file mode 100644
index 00000000..5dca7605
Binary files /dev/null and b/fig/pr-bot-workflow.png differ
diff --git a/fig/pr-diff.png b/fig/pr-diff.png
new file mode 100644
index 00000000..a341149c
Binary files /dev/null and b/fig/pr-diff.png differ
diff --git a/fig/rstudio-mac-install.png b/fig/rstudio-mac-install.png
new file mode 100644
index 00000000..cd3685e5
Binary files /dev/null and b/fig/rstudio-mac-install.png differ
diff --git a/fig/update-workflow-manual.png b/fig/update-workflow-manual.png
new file mode 100644
index 00000000..88d13e9e
Binary files /dev/null and b/fig/update-workflow-manual.png differ
diff --git a/github-pat.md b/github-pat.md
new file mode 100644
index 00000000..5f1fcb60
--- /dev/null
+++ b/github-pat.md
@@ -0,0 +1,160 @@
+---
+title: Setting Up a Personal Access Token via R
+---
+
+## I use SSH, Why should I use HTTPS?
+
+GitHub has announced that [passwords will no longer be used for authentication
+from the command line starting in August 2021](https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/).
+While you may or may not be comfortable with SSH, here a few things that may
+motivate you:
+
+1. HTTPS is recommended by both GitHub and RStudio for people starting with R,
+ so switching to HTTPS will help you empathize and demonstrate the ropes to
+ learners in the long run.
+2. HTTPS gives you more fine-grained control over what access each token gives.
+3. [RStudio Cloud](https://rstudio.cloud) is a really good platform that can
+ connect to your GitHub account if you need to work on lesson development
+ when you don't have your computer handy. You cannot use SSH with that service,
+ but it is possible to access it via HTTPS.
+4. You can connect to the GitHub API with a higher rate limit, which means that
+ you can auto-create remote repositories and analyze GitHub data without a
+ web browser.
+
+## Verifying Your Git Situation
+
+To confirm that your Git session is correctly configured, open RStudio, and run
+the following line to check if your HTTPS credentials are set up properly:
+
+```r
+library("usethis")
+git_sitrep() # git situation report
+```
+
+Pay attention to the **GitHub** report. What does it look like?
+
+
+### GitHub connected via PAT
+
+```output
+Git config (global)
+β Name: 'Zhian N. Kamvar'
+β Email: 'zkamvar@gmail.com'
+β Vaccinated: FALSE
+βΉ See `?git_vaccinate` to learn more
+β Default Git protocol: 'ssh'
+GitHub
+β Default GitHub host: 'https://github.com'
+β Personal access token for 'https://github.com': ''
+β GitHub user: 'zkamvar'
+β Token scopes: 'gist, repo, user, workflow'
+β Email(s): 'zkamvar@gmail.com (primary)', ...
+Git repo for current project
+βΉ No active usethis project
+```
+
+If your output looks like this, then you are properly set up and you are good to
+go! If not, read on!
+
+## Creating a New GitHub Personal Access Token
+
+If you see errors associated with your GitHub token (see below, e.g. 'Token is
+invalid' or 'Can't retrieve registered email address(es)'), then you should
+create a new one. Dr. Jenny Bryan wrote [an excellent resource for creating and
+caching your GitHub credentials on your computer
+](https://happygitwithr.com/https-pat.html) that
+will walk you through the process of generating a PAT, and storing it in a
+secure location. Here are the steps briefly via R:
+
+1. Create a GitHub PAT via R with `usethis::create_github_token()` (this will
+ open a page in your browser pre-populated with the appropriate scopes. If
+ this does not work, [use this link to generate a new token for
+ R][token-scope].)
+2. Copy and store the token in a password manager (Lastpass, 1Password)
+3. Back in R, use `gitcreds::gitcreds_set()` to register your token with git.
+4. Check your credentials again with `usethis::git_sitrep()`
+
+At this point, you should have things set up properly. If you are still having
+problems, you can try the following two steps (after you have your PAT):
+
+1. in R, use `credentials::git_credential_forget()` to clear the cache
+2. use `credentials::set_github_pat()` and paste your token.
+
+::::::::: discussion
+
+### Common Token Errors
+
+There are a few possible errors you might see, but the remedy is always the same:
+get a new token and register it in your credentials keychain.
+
+#### Invalid Personal Access Token
+
+Invalid tokens can come from old tokens that were deleted from your GitHub
+account.
+
+```output
+Git config (global)
+β Name: 'Zhian N. Kamvar'
+β Email: 'zkamvar@gmail.com'
+β Vaccinated: FALSE
+βΉ See `?git_vaccinate` to learn more
+β Default Git protocol: 'ssh'
+GitHub
+β Default GitHub host: 'https://github.com'
+β Personal access token for 'https://github.com': ''
+β Token is invalid
+β Can't retrieve registered email address(es)
+ If you are troubleshooting, check GitHub host, token, and token scopes
+Git repo for current project
+βΉ No active usethis projectw
+```
+
+#### Password as Token
+
+This error often means that you have your password stored in your keychain
+instead of your token. This seems like a weird error until you realize that
+GitHub will stop allowing password authentication from the command line in
+August 2021.
+
+```output
+Git config (global)
+β Name: 'Zhian N. Kamvar'
+β Email: 'zkamvar@gmail.com'
+β Vaccinated: FALSE
+βΉ See `?git_vaccinate` to learn more
+β Default Git protocol: 'ssh'
+GitHub
+β Default GitHub host: 'https://github.com'
+Error: GitHub PAT must have one of these forms:
+ * 40 hexadecimal digits (older PATs)
+ * A 'ghp_' prefix followed by 36 to 251 more characters (newer PATs)
+Type .Last.error.trace to see where the error occured
+```
+
+#### No Personal Access Token Detected
+
+This means you have not registered a Personal Access Token with git and are good
+to start fresh!
+
+```output
+β Name: 'Zhian N. Kamvar'
+β Email: 'zkamvar@gmail.com'
+β Vaccinated: FALSE
+βΉ See `?git_vaccinate` to learn more
+β Default Git protocol: 'ssh'
+GitHub
+β Default GitHub host: 'https://github.com'
+β Personal access token for 'https://github.com':
+β Call `gh_token_help()` for help configuring a token
+Git repo for current project
+βΉ No active usethis project
+```
+
+::::::::::::::::::::::::
+
+
+
+[R]: https://cran.rstudio.org/
+[token-scope]: https://github.com/settings/tokens/new?scopes=repo,user,gist,workflow&description=R:GITHUB_PAT
+[pandoc]: https://pandoc.org/
+[RStudio]: https://rstudio.com/products/rstudio/download/#download
diff --git a/index.md b/index.md
new file mode 100644
index 00000000..1dbbb42a
--- /dev/null
+++ b/index.md
@@ -0,0 +1,36 @@
+---
+site: sandpaper::sandpaper_site
+---
+
+
+Welcome to the documentation for The Carpentries Workbench. This is a
+complete redesign of our lesson infrastructure (formerly known as the lesson template)
+that follows the philosophy of keeping content and tools separate.
+The new infrastructure will have the following features:
+
+:::::::::::::::::: checklist
+
+## Features of the The Carpentries Workbench
+
+- [x] Automatic updates
+- [x] Pandoc markdown syntax
+- [x] Built entirely using R
+- [x] Automatic rendering of R Markdown
+- [x] Non-invasive package management with {renv}
+- [x] Pull Request audits for rendered files
+- [x] Compatible with RStudio
+
+::::::::::::::::::::::::::::
+
+
+:::::: callout
+
+### :construction: Under Construction :construction:
+
+This documentation site is still being constructed---please be patient.
+
+If you are looking to get started using the workbench, head over to the
+[setup](learners/setup.md) page to get started!
+
+::::::::::::::::::
+
diff --git a/instructor-notes.md b/instructor-notes.md
new file mode 100644
index 00000000..ca38e484
--- /dev/null
+++ b/instructor-notes.md
@@ -0,0 +1,6 @@
+---
+title: Instructor Notes
+---
+
+Just remember to breathe at the moment.
+
diff --git a/instructor.md b/instructor.md
new file mode 100644
index 00000000..27a8f970
--- /dev/null
+++ b/instructor.md
@@ -0,0 +1,17 @@
+---
+title: Instructor Profiles
+---
+
+We have a vast and diverse instructor community with varying levels of expertise.
+These profiles will help us understand their motivations for using the lesson
+template
+
+
+:::::::::::::::::: callout
+
+### Under Construction
+
+Profiles are still being constructed. If you can, help out by clicking the
+"Edit on GitHub" link below and submit a profile!
+
+::::::::::::::::::::::::::
diff --git a/introduction.md b/introduction.md
new file mode 100644
index 00000000..31e8af35
--- /dev/null
+++ b/introduction.md
@@ -0,0 +1,306 @@
+---
+title: "Introduction to The Carpentries Workbench"
+teaching: 10
+exercises: 2
+---
+
+:::::::::::: questions
+
+ - How do I get started?
+
+::::::::::::::::::::::
+
+::::::::::: objectives
+
+- Create new lesson from scratch
+- Identify the main command to preview the site
+- Understand the basic structure of a new workbench
+
+::::::::::::::::::::::
+
+Let's say you have a set of Markdown or R Markdown files that you used for a
+class website that you want to convert into a Carpentries Lesson. To go from
+zero to a new lesson website that can auto-render R Markdown documents to a
+functional website is three steps with `{sandpaper}`:
+
+1. Create a site
+2. Push to GitHub
+3. Add your files
+
+That's it. After that, if you know how to write in Markdown, you are good to go.
+
+:::::::::::::::::: callout
+
+### Takeaway message
+
+Contributors should only be expected to know basic markdown and *very* minimal
+yaml syntax in order to work on lessons.
+
+:::::::::::::::::::::::::::
+
+## Super Quickstart: Copy A Template from GitHub
+
+The absolute quickest way to get started with The Carpentries Workbench is to
+create a GitHub repository with one of the two available templates, depending on
+your preference:
+
+### Step 1: Choose a template
+
+ - [Markdown Lessons (no generated content)](https://github.com/carpentries/workbench-template-md/generate) (if your lesson will not include R code examples, use this template)
+ - [R Markdown Lessons (generated content via R)](https://github.com/carpentries/workbench-template-rmd/generate) (our tutorial uses this template)
+
+### Step 2: Choose a name for your lesson repository.
+
+Name it "buoyant-barnacle". **select "Include All Branches"**. Click on
+the button that says "Create repository from template"
+
+::::::::::::: callout
+
+#### Creating a new lesson repository
+
+![What you should see when you click on one of the above two links](fig/intro-template-screen.png){alt="Screenshot of a webform that says
+'Create a new repository from workbench-template-md'. It says that the new
+repository will contain the same files and folders as
+carpentries/workbench-template-md and has two required fields for Owner and
+Repository Name, which are filled in as ravmakz and buoyant-barnacle. There
+is a blank Description option, a radio button that selects public/private, and
+an checked checkbox to include all branches"}
+
+::::::::::::::::::::
+
+### Step 3: Customise your site
+
+On GitHub, open the `config.yaml` file, and click on the pencil icon on the top
+and edit the values, especially "carpentry", "source", and "title" to reflect
+your own repository. Commit the file using the form at the bottom of the page.
+
+That's it. The website should update in about 2-3 minutes with your information.
+If you want to continue working directly on GitHub, you can do so. If you want to
+work locally, be sure to [follow the setup instructions][setup], clone your
+lesson to your computer, open RStudio (or your preferrred interface to R) inside
+the lesson folder, and [preview your new lesson](#preview)
+
+## Quickstart: Create a New Lesson
+
+:::::::::::::::::::::::::::: challenge
+
+### Create a Lesson Locally
+
+Follow these steps to create a brand new lesson on your Desktop called
+"buoyant-barnacle".
+
+1. Follow the [setup instructions][setup]
+2. Open RStudio (or your preferred interface to R)
+3. Use the following code:
+
+```r
+library("fs") # file system package for cross-platform paths
+library("sandpaper")
+
+# Create a brand new lesson on your desktop called "buoyant-barnacle"
+bb <- path_home("Desktop/buoyant-barnacle")
+print(bb) # print the new path to your screen
+create_lesson(bb) # create a new lesson in that path
+```
+
+If everything went correctly, you will now have a new RStudio window open to
+your new project called "buoyant-barnacle" on your Desktop (if you did not use
+RStudio, your working directory should have changed, you can check it via the
+`getwd()` command).
+
+::::::::::::::::::::::::::::::::::
+
+Your lesson will be initialized with a brand new git repository with the initial
+commit message being `Initial commit [via {sandpaper}]`.
+
+:::::::::::::::::::::: callout
+
+### :beetle: Known Quirk
+
+If you are using RStudio, then an RStudio project file (`*.Rproj`) is
+automatically created to help anchor your project. You might notice changes to
+this file at first as RStudio applies your global user settings to the file.
+This is perfectly normal and we will fix this in a future iteration of
+{sandpaper}.
+
+::::::::::::::::::::::::::::::
+
+## Previewing Your New Lesson {#preview}
+
+After you created your lesson, you will want to preview it locally. First, make
+sure that you are in your newly-created repository and then use the following
+command:
+
+```r
+sandpaper::serve()
+```
+
+:::::::::::::::: discussion
+
+### What's with the `::` syntax?
+
+This is a syntax that clearly states what package a particular function comes
+from. In this case, `sandpaper::serve()` tells R to use the `serve()` function
+from the `sandpaper` package. These commands can be run without first calling
+`library()`, so they are more portable. I will be using this
+syntax for the rest of the lesson.
+
+:::::::::::::::::::::::::::
+
+If you are working in RStudio, you will see a preview of your lesson in the
+viewer pane and if you are working in a different program, a browser window will
+open, showing a live preview of the lesson. When you edit files, they will
+automatically be rebuilt to your website.
+
+:::::::::::::: callout
+
+### DID YOU KNOW? Keyboard Shortcuts are Available
+
+If you are using RStudio, did you know you can use keyboard shortcuts to render
+the lesson as you are working on the episodes?
+
+Render and preview the whole lesson
+: ctrl + shift + B
+
+Render and preview an episode
+: ctrl + shift + K
+::::::::::::::::::::::
+
+The first time you run this function, you might see A LOT of output on your
+screen and then your browser will open the preview. If you run the command
+again, you will see much less output. If you like to would like to know how
+everything works under the hood, you can check out the [{sandpaper} package
+documentation][{sandpaper}].
+
+::::::::::::::::::::::::::::::::::::: discussion
+
+### How do I determine the order of files displayed on the website?
+
+The `config.yaml` file contains four fields that correspond to the folders in
+your repository: `episodes`, `instructors`, `learners`, `profiles`. If the list
+is empty, then the files in the folders are displayed in alphabetical order,
+but if you want to customize exactly what content is published on the website,
+you can add a yaml list of the filenames to determine order.
+
+For example, if you had three episodes called "introduction.md", "part_two.Rmd",
+and "in_progress.md" and you wanted to only show introduction and part_two, you
+would edit `config.yaml` to list those two files under `episodes:`:
+
+```yaml
+episodes:
+- introduction.md
+- part_two.Rmd
+```
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+## Push to GitHub
+
+The lesson you just created lives local on your computer, but still needs to go
+to GitHub. At this point, we assume that you have successfully [linked your
+computer to GitHub](../learners/setup.md#connect-to-github-1).
+
+1. visit
+2. enter `buoyant-barnacle` as the repository name
+3. Press the green "Create Repository" button at the bottom of the page
+4. Follow the instructions on the page to push an existing repository from the
+ command line.
+
+
+A few minutes after you pushed your repository, the GitHub workflows would have
+validated your lesson and created deployment branches. You can track the
+progress at `https://github.com//buoyant-barnacle/actions/`. Once you
+have a green check mark, you can [set up GitHub
+Pages](https://docs.github.com/en/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site)
+by going to `https://github.com//buoyant-barnacle/settings/pages` and
+choosing `gh-pages` from the dropdown menu as shown in the image below:
+
+![](fig/github-pages-none.png){.image-with-shadow alt='screencapture of the
+initial view of the GitHub Pages section of the settings tab'}
+
+Click on the "select branch" button and select "gh-pages", then click "Save":
+
+![](fig/github-pages-gh-pages.png){.image-with-shadow alt='screencapture of
+expanded "select branch" button with "gh-pages" selected'}
+
+After completing this configuration,
+the URL for your lesson website will be displayed at the top of the page.
+Site URLs can be customised, but the default URL structure is
+`https://.github.io//`:
+the URL of the `buoyant-barnacle` example used so far would be
+`https://.github.io/buoyant-barnacle/`.
+
+::::::::::::: callout
+
+### :hourglass: Be Patient
+
+GitHub needs to start up a new virtual machine the first time you use this, so
+it may take anywhere from 4 minutes up to 30 minutes for things to get started:
+15 minutes for the workflow to spin up and then another 15 minutes for the
+machine to bootstrap and cache.
+
+::::::::::::::::
+
+
+:::::::::::: callout
+
+### Alternative: Two-step solution in R
+
+If you use R and use an HTTPS protocol, this can be done in a single step from
+inside RStudio with the {usethis} package:
+
+```r
+usethis::use_github()
+usethis::use_github_pages()
+```
+
+The `use_github()` function will set up a new repository under your personal
+account called `buoyant-barnacle`, add that remote to your `git remotes`, and
+automatically push your repository to GitHub.
+
+The `use_github_pages()` function will signal to GitHub that it should allow
+the `gh-pages` branch to serve the website at
+`https://user.github.io/buoyant-barnacle`
+
+The output of these commands should look something like this:
+
+```output
+> use_github()
+β Creating GitHub repository 'zkamvar/buoyant-barnacle'
+β Setting remote 'origin' to 'https://github.com/zkamvar/buoyant-barnacle.git'
+β Pushing 'main' branch to GitHub and setting 'origin/main' as upstream branch
+β Opening URL 'https://github.com/zkamvar/buoyant-barnacle'
+
+> use_github_pages()
+β Initializing empty, orphan 'gh-pages' branch in GitHub repo 'zkamvar/buoyant-barnacle'
+β GitHub Pages is publishing from:
+β’ URL: 'https://zkamvar.github.io/buoyant-barnacle/'
+β’ Branch: 'gh-pages'
+β’ Path: '/'
+```
+
+If you don't use the HTTPS protocol, and want to find out how to set it in R,
+we have [a walkthrough to set your credentials in the learners section
+](../learners/github-pat.md).
+
+::::::::::::::::::::
+
+## Tools
+
+As described in [the setup document][setup], The Carpentries Workbench only
+requires R and [pandoc] to be installed. The tooling from the styles lesson
+template has been split up into three R packages:
+
+1. [{varnish}] contains the HTML, CSS, and JavaScript elements
+1. [{pegboard}] is a validator for the markdown documents
+1. [{sandpaper}] is the engine that puts everything together.
+
+::::::::::::: keypoints
+
+- Lessons can be created with `create_lesson()`
+- Preview lessons with `serve()`
+- The toolchain is designed to be modular.
+
+:::::::::::::::::::::::
+
diff --git a/links.md b/links.md
new file mode 100644
index 00000000..db78be9a
--- /dev/null
+++ b/links.md
@@ -0,0 +1,14 @@
+[{varnish}]: https://github.com/carpentries/varnish/
+[{pegboard}]: https://carpentries.github.io/pegboard/
+[{sandpaper}]: https://carpentries.github.io/sandpaper/
+[pandoc]: https://pandoc.org/
+[setup]: ../learners/setup.md
+[r-markdown]: https://rmarkdown.rstudio.com/
+[carpentries-workbench]: https://carpentries.github.io/sandpaper-docs
+[rmd-blog]: https://software-carpentry.org/blog/2016/07/rmarkdown-new-template.html
+[r4-migration]: https://carpentries.org/blog/2020/08/r-4-migration/
+[gh-workflows]: https://docs.github.com/en/actions/
+[pandoc-md]: https://pandoc.org/MANUAL#pandocs-markdown
+[fenced-divs]: https://pandoc.org/MANUAL#divs-and-spans
+[basic-syntax]: https://www.markdownguide.org/basic-syntax
+[extended-syntax]: https://www.markdownguide.org/extended-syntax/
diff --git a/maintainer.md b/maintainer.md
new file mode 100644
index 00000000..57249d18
--- /dev/null
+++ b/maintainer.md
@@ -0,0 +1,38 @@
+---
+title: Maintainer Profiles
+---
+
+Our maintainer community is full of individual with different motivations for
+maintaining lessons. This page will catalog some maintainer profiles so that
+we can identify how we can make the template easy to use for them.
+
+## General Maintainers
+
+Tamar Teosinte --- Pythonista, Machine Learning, Maize Genetics
+: Tamar is a graduate student maize geneticist who has developed a machine
+learning algorithm to rapidly identify color changes in maize kernels that
+identify tagged transposable genetic elements. She knows many students in her
+field who could benefit from knowing how to write reproducible python
+workflows, so she applies and becomes a maintainer for the [Plotting and
+Programming with Python] lesson. She is proficient with Git, GitHub, and
+Python. She has used R in her undergraduate statistics course, but has not used
+it since. She uses the VSCode IDE and Anaconda Python for her work.
+
+## R Maintainers
+
+:::::::: callout
+
+### FILL ME WITH WONDERFUL STORIES!
+
+:::::::::::::
+
+## Incubator Maintainers
+
+:::::::::::: callout
+
+### FILL ME WITH WONDERFUL STORIES!
+
+::::::::::::::::::::
+
+
+[Plotting and Programming with Python]: https://swcarpentry.github.io/python-novice-gapminder/
diff --git a/md5sum.txt b/md5sum.txt
new file mode 100644
index 00000000..912a2763
--- /dev/null
+++ b/md5sum.txt
@@ -0,0 +1,23 @@
+"file" "checksum" "built" "date"
+"CODE_OF_CONDUCT.md" "8d9e44dd5c39f241b5e8b47ecfc802d1" "site/built/CODE_OF_CONDUCT.md" "2024-10-18"
+"LICENSE.md" "b24ebbb41b14ca25cf6b8216dda83e5f" "site/built/LICENSE.md" "2024-10-18"
+"config.yaml" "3e1f5d33d43d4398c6f6bf660c0e88d0" "site/built/config.yaml" "2024-10-18"
+"index.md" "4d117199b579f6901292749f1a414a00" "site/built/index.md" "2024-10-18"
+"links.md" "a7ea11385a9d821b8f57edb0951c83ca" "site/built/links.md" "2024-10-18"
+"episodes/introduction.md" "b1ca0d51bfee1538beabc08f46b389cf" "site/built/introduction.md" "2024-10-18"
+"episodes/episodes.Rmd" "4f9401544dcfcd6d0ba5b61dca806f04" "site/built/episodes.md" "2024-10-18"
+"episodes/editing.md" "7b5d6a45cfe297d06bf61326bea97251" "site/built/editing.md" "2024-10-18"
+"episodes/example.Rmd" "215e3c4ed500fef3410f040349fb0a73" "site/built/example.md" "2024-10-18"
+"episodes/deployment.md" "f15377cac190ef5435a60d074aa8aeb3" "site/built/deployment.md" "2024-10-18"
+"episodes/update.md" "e3939117fb9b893806c4f43e7f08594e" "site/built/update.md" "2024-10-18"
+"episodes/pull-request.md" "2afffbb78274f9054f55cc7756c9ee03" "site/built/pull-request.md" "2024-10-18"
+"instructors/instructor-notes.md" "52cc20bd20dc02bf0f9df0f583a6c2ff" "site/built/instructor-notes.md" "2024-10-18"
+"learners/reference.md" "3eeb20922176cd8397cbe420532fd21c" "site/built/reference.md" "2024-10-18"
+"learners/setup.md" "05817abf165dd794bf9684653749a00a" "site/built/setup.md" "2024-10-21"
+"learners/github-pat.md" "65a2c6f46233a1335a6fc0392cb8a405" "site/built/github-pat.md" "2024-10-18"
+"learners/component-guide.md" "acd50b728fc8f6c9945e7fe7962da61b" "site/built/component-guide.md" "2024-10-18"
+"learners/migrating-from-styles.md" "68dd61e4d88734fbf0ce9d3237080ebc" "site/built/migrating-from-styles.md" "2024-10-18"
+"learners/style.md" "59a4d847201ced45d9b78b8ec9b05993" "site/built/style.md" "2024-10-18"
+"profiles/maintainer.md" "2a2b790c0aa8da5fb72e323e4fafabd9" "site/built/maintainer.md" "2024-10-18"
+"profiles/instructor.md" "ff8c586028a5e1c7ef0be4178b40417c" "site/built/instructor.md" "2024-10-18"
+"renv/profiles/lesson-requirements/renv.lock" "3ea26836eaffefbe2e2587fd1be28c99" "site/built/renv.lock" "2024-10-18"
diff --git a/migrating-from-styles.md b/migrating-from-styles.md
new file mode 100644
index 00000000..d7a40a1c
--- /dev/null
+++ b/migrating-from-styles.md
@@ -0,0 +1,223 @@
+---
+title: Migrating lessons from the previous infrastructure
+---
+
+This page describes a workflow for semi-automated transition from The Carpentries old infrastructure to the Workbench.
+It is based on the transition workflows and documentation originally written by [Zhian Kamvar](https://github.com/zkamvar/). See the full set of lesson transition scripts and documentation at .
+Please contact [The Carpentries Curriculum Team](mailto:curriculum@carpentries.org) with questions about this workflow.
+
+The workflow is intended for use by Carpentries community members who want to transition their own lesson repository from the old "styles" infrastructure to use the Workbench.
+
+After following this process you will have replaced the contents of your current lesson repository with a Workbench version containing the same lesson content.
+
+::: callout
+**_We strongly recommend that you create a backup of your lesson repository before you follow this workflow._**
+:::
+
+:::::::: prereqs
+
+## Prerequisites
+
+Before following the steps described below, please make sure that you have done the following:
+
+1. Enabled push access to GitHub from the command line on your local system: you will need to have SSH or HTTPS access configured to allow you to push changes to your GitHub repository from the command line. See [_Authenticating with the command line_](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-authentication-to-github#authenticating-with-the-command-line) in GitHub's documentation for more details and step-by-step guides.
+2. Merged or closed all open pull requests on your lesson repository. Any open pull requests will be rendered invalid by the migration between infrastructures.
+3. Installed Git and R on your local system. The workflow described below assumes that you can call R as a command from a Bash shell session.
+4. (Optional, but highly recommended) archived a final version of your lesson in the old infrastructure. Although this workflow has been documented with recommendations to minimise the chances of accidentally overwriting your lesson with anything other than a fully-tranisitoned equivalent, it is still wise to ensure that you have a complete and up-to-date copy of your lesson as a backup. For example, you could publish a release to [Zenodo](https://zenodo.org/).
+5. (Optional, but highly recommended) created or synced up a fork of the lesson. This can be used to test the transitioned lesson on GitHub before making the final, irreversible changes to your primary lesson repository. The fork only needs to contain a copy of the default branch of your lesson (usually `gh-pages`).
+
+:::::::::::::::::
+
+---
+
+## Transition Workflow
+
+1. [Set up the transition tools](#workflow-setup)
+2. [Create an Rscript for your lesson](#Rscript)
+3. [Run the transition tool](#transition)
+4. [Set up your GitHub repository to receive the transitioned lesson](#github)
+5. [Post-transition steps](#post-transition)
+
+::: callout
+Note: these steps assume your lesson exists in The Carpentries Incubator i.e. under the `carpentries-incubator` organisation on GitHub. If it does not, you will need to replace all of the folder names etc below accordingly.
+:::
+
+### 1. Set up the transition tools{#workflow-setup}
+
+1. Open a Bash shell and run the following:
+
+ ```bash
+ git clone https://github.com/carpentries/lesson-transition.git && cd lesson-transition
+ git switch -c YOUR-LESSON-NAME-transition # provide a branch name appropriate for your lesson, e.g. for the carpentries-incubator/docker-introduction lesson, you would call the branch docker-introduction-transition
+ git submodule update --init git-filter-repo # this will ensure the git-filter-repo tool is available
+ ```
+
+2. Install dependencies for lesson transition tool:
+ - If you already have `renv` installed on your system: open R in this directory (run the `R` command in Bash), answer `y` to the prompt `Would you like to restore the project library?`, wait for the project setup to complete, then exit R
+ - If you do not yet have `renv` installed: open R in this directory (run the `R` command in Bash), then run the following:
+
+ ```R
+ install.packages('renv') # enter 'y' to complete the installation
+ library('renv')
+ renv::restore()
+ ```
+
+ or run the following commands in Bash:
+
+ ```bash
+ Rscript -e "install.packages('renv')" # enter 'y' to complete the installation
+ Rscript -e "library('renv')"
+ Rscript -e "renv::restore()"
+ ```
+
+3. Returning to Bash (you can quit R by calling the `q()` function), run the following:
+
+ ```bash
+ Rscript establish-template.R template/
+ git submodule add --force -b gh-pages https://github.com/carpentries-incubator/YOUR-LESSON-NAME carpentries-incubator/YOUR-LESSON-NAME # replace YOUR-LESSON-NAME with the name of your lesson, and replace 'gh-pages' with 'main' if main is the default branch for your lesson
+ ```
+
+### 2. Create an Rscript for your lesson{#Rscript}
+The transition tool requires an R script to exist for any lesson it migrates to the new infrastrucure. In the large-scale transition of Carpentries lessons, these R scripts were used to handle various edge cases, customisations to the standard Markdown syntax, etc that existed in every lesson but were unique to each.
+
+The script is run on the version of the Workbench lesson created by the transition tool, as a kind of post-processing step before the changes made by the transition are committed. Any changes made by the script will appear as if carried out by the transition tool, thereby avoiding additional commits in your project history associated with "cleaning up" after the migration.
+
+It is sufficient to create an empty file, named appropriately. This is available in the add-lesson.sh file, which will also provide hints about how the data can be transformed.
+
+```bash
+bash add-lesson.sh carpentries-incubator/YOUR-LESSON-NAME
+```
+
+But you may wish to populate this script with some function calls to clean up various common artifacts produced by the transition, or to preserve any [custom workflows](#custom-workflows) you have added to your lesson repository. Look at the `.R` scripts in the [`carpentries-incubator/`](https://github.com/carpentries/lesson-transition/tree/main/carpentries-incubator), [`datacarpentry`](https://github.com/carpentries/lesson-transition/tree/main/datacarpentry), [`librarycarpentry`](https://github.com/carpentries/lesson-transition/tree/main/librarycarpentry), and [`swcarpentry`](https://github.com/carpentries/lesson-transition/tree/main/swcarpentry) directories of the `lesson-transition` repository for inspiration.
+
+### 3. Run the transition tool{#transition}
+
+#### Try this first
+
+In Bash, run the release process via `make` to save yourself some work:
+
+```bash
+make release/carpentries-incubator/YOUR-LESSON-NAME.json
+```
+
+::: callout
+Notes:
+
+* the `YOUR-LESSON-NAME.json` file does not need to exist for these commands to run
+* if you would like to run a test first, you can use `make sandpaper/carpentries-incubator/YOUR-LESSON-NAME.json`, which will create a 'beta test' version of the transitioned lesson in the `carpentries-incubator` folder.
+:::
+
+#### If that doesn't work...
+
+Try running the process step-by-step:
+
+1. In Bash, run:
+
+ ```bash
+ bash filter-and-transform.sh release/carpentries-incubator/YOUR-LESSON-NAME.json carpentries-incubator/YOUR-LESSON-NAME.R $(readlink -f ./filter-list.txt) 'return message'
+ cd release/carpentries-incubator/YOUR-LESSON-NAME
+ LESSONNAME=`pwd | rev | cut -d/ -f1 | rev`
+ for FILENAME in commit-map ref-map suboptimal-issues
+ do
+ cp .git/filter-repo/$FILENAME ../$LESSONNAME-$FILENAME.hash
+ done
+ egrep ' 0{40}$' .git/filter-repo/commit-map | cut -d' ' -f1 | head -1 > ../$LESSONNAME-invalid.hash
+ if [ ! -s ../$LESSONNAME-invalid.hash ]; then rm ../$LESSONNAME-invalid.hash;fi
+ ```
+2. Adjust lesson config file
+ * **Option 1 (manual):** Using your favourite text editor, open the `config.yaml` file and remove the lines setting the `workbench-beta`, `analytics`, `lang`, and `url` parameters.
+ * **Option 2 (using regular expressions):** In Bash, run:
+
+ ```bash
+ grep -v -E '^workbench-beta|^analytics|^lang|^url' config.yaml > config-filtered.yaml && mv config-filtered.yaml config.yaml
+ ```
+3. Set the correct address for your origin remote repository. In Bash, run:
+
+ ```bash
+ git remote set-url origin ADDRESS-OF-YOUR-REMOTE # replace ADDRESS-OF-YOUR-REMOTE to set origin to the correct address for your lesson repository on GitHub
+ ```
+
+::: callout
+
+### Custom workflow files{#custom-workflows}
+The contents of the `.github` folder are not preserved by the transition tool. If you had any custom workflow files in your lesson repository before migrating to the new infrastructure, you will need to add those back into `.github/workflows/` at this point then commit the changes. (You could also modify the Rscript for your lesson transition to do this for you, and repeat the transition process to include it.)
+
+:::
+
+
+#### Build and check your transitioned lesson
+At this stage, the `release/carpentries-incubator/YOUR-LESSON-NAME/` directory should contain a transitioned version of your lesson.
+To check how things are looking, [install the Workbench tools for your system](index.html#installation), then open R in this directory and run `sandpaper::serve()`.
+
+#### Optional: update your lesson's R script to produce a smoother transition
+While previewing this transitioned lesson site, you might see some problems in the content of your lesson site that appeared during the migration. Liquid comments (delineated by `{% comment %}` and `{% endcomment %}` tags) are one commonly-encountered artifact. Another is broken links to the lesson setup instructions, which are found at `index.html#setup` in a Workbench site. These can be fixed by editing the lesson after transition, but for a cleaner commit history on your lesson you might wish to delete the transitioned lesson directory (inside the `release` folder), modify the R script for your lesson to handle those issues, and re-run the transition tool. (See [_Create an Rscript for your lesson_](#Rscript) above.)
+
+#### If something goes wrong
+To go back to the start and try again, delete the directory for your lesson within the `release/` directory, i.e. `rm -rf release/carpentries-incubator/YOUR-LESSON-NAME`.
+
+If the transition tool ran successfully but your lesson build fails, this is usually due to customisations made to the lesson that fall outside what the transition tool expected to find.
+If you run into problems, we recommend that you try to identify differences between yours and a typical lesson repository (the [Workbench Markdown template](https://github.com/carpentries/workbench-template-md) and [R Markdown template](https://github.com/carpentries/workbench-template-rmd) are good examples) and experiment to see if any of those are causing the site build to fail.
+
+If something goes wrong and you cannot debug the problem on your own, post a message to the `#workbench` channel on The Carpentries Slack workspace, or reach out to the Curriculum Team by email (curriculum@carpentries.org). Try to provide as much information as you can, including any error messages and logging information that were produced when you ran the steps described above. We will do our best to help you but please note that the Core Team's capacity to provide support for transition of community lessons is severely limited.
+
+### 4. Set up your GitHub repository to receive the transitioned lesson{#github}
+
+::: callout
+**We recommend that you try these steps out on a fork of your lesson first**, so that you can be certain everything works before making permanent changes to your main lesson repository.
+:::
+
+1. Adjust the `config.yaml`:
+ - Record your lesson creation date in config.yaml: run `git log` and hit Shift+G to jump to end of file, note down the date when the first commit was made. Then, using your favourite text editor, open `config.yaml` and modify the `created` field by replacing `~` with this creation date in YYYY-MM-DD format.
+ - Check the `source` URL specified in `config.yaml`: this may be set incorrectly during the transition process. Adjust it to the correct URL for your lesson source repository on GitHub.
+
+3. Commit the changes you made to the lesson config file:
+
+ ```bash
+ git add config.yaml
+ git commit -m 'complete configuration of Workbench lesson site'
+ ```
+
+4. Rename the branches of your project:
+ - On your GitHub repository, rename the `gh-pages` branch to `legacy/gh-pages` (if `main` is your default branch, also rename that to `legacy/main`).
+ - Branches can be renamed by going to the list of all branches on your repository (add `/branches/all` to the end of the URL for your GitHub repository e.g. ) and selecting the pencil icon button next to the relevant branch in that listing.
+5. In Bash on your local system (make sure you are working in the root of the `release/carpentries-incubator/YOUR-LESSON-NAME` directory), run the following commands (please read the comments that annotate these commands and note that **we strongly recommend that you execute these one-at-a-time!**):
+
+ ```bash
+ git remote -v # check the names and addresses of your remote repositories: if you are testing on a fork and it is not listed here, add it with 'git remote add' https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emaddem
+ git fetch --prune origin # this assumes your remote is called origin - if you are testing on a fork, use the name of that remote here instead
+ git checkout --orphan gh-pages # set up gh-pages branch
+ # double-check that you are in the root of your lesson within the lesson-transition/release folder (e.g. if transitioning carpentries-incubator/docker-introduction, you should be in lesson-transition/release/carpentries-incubator/docker-introduction/)
+ git rm -rf .
+ mkdir -p .github/workflows/
+ curl -o .github/workflows/close-pr.yaml https://raw.githubusercontent.com/carpentries/lesson-transition/main/close-pr.yaml # download the workflow that will auto-close invalid PRs to gh-pages
+ git add .github/workflows/close-pr.yaml
+ git commit --allow-empty -m 'Initialising gh-pages branch'
+ git push --force origin HEAD:gh-pages
+ ```
+
+6. If everything has gone well up to this point, it is time to go back to the `main` branch and force push its contents to GitHub:
+
+ ```bash
+ git switch main
+ git push --force --set-upstream origin main # force push the transitioned main branch to your GitHub repository
+ ```
+
+7. On your GitHub repository:
+ - set the default branch to `main` (in Settings->General, click the button with two arrows next to the name of the default branch)
+ - in Settings->Branches, add rules to protect the `main` branch (require pull requests) and lock `legacy/*`
+ - make sure that your lesson site is being served with GitHub Pages from the root folder of the gh-pages branch (in Settings->Pages, under _Build and deployment_, ensure that `gh-pages` is selected with the dropdown under _Branch_ and that `/ (root)` is the folder selected, then hit the _Save_ button)
+
+If all of the above worked, you should now have a Workbench version of your lesson.
+
+### 5. Post-transition steps{#post-transition}
+
+After you have transitioned your lesson, you should:
+
+1. **Delete and re-create any forks and local clones** of your lesson project, to minimise the likelihood that you will accidentally push the old project history back to the GitHub repository. If you have any collaborators and fellow lesson developers/maintainers, ask them to do the same.
+2. If your lesson is in The Carpentries Incubator, [**tell the Curriculum Team**](mailto:curriculum@carpentries.org) that you have completed the transition so that we can activate the automated creation of pull requests to update the Workbench infrastructure when new versions of the packages are released.
+3. (Optional, but highly recommended) Open a pull request to https://github.com/carpentries/reactables/ to **add the invalid commit hash** (in the `invalid.hash` file created for your lesson during the transition (step 3 above)) to [the `workbench/invalid-hashes.json` file](https://github.com/carpentries/reactables/blob/main/workbench/invalid-hashes.json). This will include the hash in the data feed used by our infrastructure to support the GitHub Actions workflow that will automatically close any pull requests opened to your repository from a branch containing the old project history. To do this:
+ * Make a fork of [the `carpentries/reactables` GitHub repository](https://github.com/carpentries/reactables/)
+ * On a new branch of that fork, edit the `workbench/invalid-hashes.json` file, adding a new line before the final `}` line matching the format of the other lines containing hashes, i.e.
+ `"carpentries-incubator/YOUR-LESSON-NAME": "HASHASHASHASHASHASHASH"`
+ where `HASHASHASHASHASHASHASH` is the hash contained in the `release/carpentries-incubator/YOUR-LESSON-NAME-invalid.hash` file created during the infrastructure transition. Make sure to add a comma `,` to the end of the preceding line to ensure the validity of the JSON file.
+ * commit the change, then open a pull request back to `carpentries/reactables` to suggest that we merge your invalid hash into our data feed. A member of the Curriculum Team will review and merge your changes.
diff --git a/pull-request.md b/pull-request.md
new file mode 100644
index 00000000..746e383c
--- /dev/null
+++ b/pull-request.md
@@ -0,0 +1,257 @@
+---
+title: "Auditing Pull Requests"
+teaching: 5
+exercises: 0
+---
+
+::::::::::::::::::::::::::::: questions
+
+ - What happens during a pull request?
+ - How do I review generated content of a pull request?
+ - How do I handle a pull request from a bot?
+
+:::::::::::::::::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::: objectives
+
+ - Identify key features of a pull request to review
+ - Identify the benefits of pull request comments from a bot
+ - Understand why bots will initiate pull requests
+ - Understand the purpose of automated pull requests
+
+::::::::::::::::::::::::::::::::::::::::
+
+## Introduction
+
+One of the biggest benefits of working on a Carpentries Lesson is that it gives
+maintainers and contributors practice collaboratively working on GitHub and
+practicing common software engineering practices, including pull requests and
+reviews. In the Carpentries Workbench, we have implemented new
+features that will make reviewing contributed content easier for maintainers:
+
+1. Source content is checked for valid headings, links, and images
+2. Generated content is rendered to markdown and placed in a temporary branch
+ for visual inspection.
+3. Pull requests are checked for malicious attacks.
+
+## Reviewing A Pull Request
+
+When you recieve a pull request, a check will first validate that the lesson can
+be built and then, if the lesson can be built, it will generate output and leave
+[a comment that provides information about the rendered
+output](https://github.com/carpentries/sandpaper-docs/pull/60#issuecomment-923204714):
+
+
+
+![](fig/pr-bot-comment.png){alt="Screenshot of GitHub bot comment informing you
+the message is automated, that you should check for accuracy of rendered output,
+and that there were 3 files changed in the rendered markdown documents."}
+
+With this information, you can click on the link that says 'Inspect the changes'
+to navigate to a diff of the rendered files. In this example, we have
+manipulated the output of a plot, and GitHub allows us to visually inspect these
+differences by scrolling down to the file mentioned in the diff and clicking on
+the "file" icon to the top right, which indicates to "display the rich diff".
+
+![](fig/pr-diff.png){alt="Screeshot of a GitHub rich diff showing two versions
+of a pyramid, one with a blue sky and yellow pyramid and the other with a yellow
+sky and lavender pyramid."}
+
+::::: callout
+
+### Living with Entropy
+
+In R Markdown documents, If you use any sort of code that generates random numbers, you may end up with small changes that show up on the list of changed files. See this example where [using the `ggplot2` function `geom_jitter()` leads to slightly different image files](https://github.com/MCMaurer/Rewrite-R-ecology-lesson/pull/3). You can fix this by setting a seed for the random number generator (e.g. `set.seed(1)`) at the beginning of the episode, so that the same random numbers are generated each time the lesson is built.
+
+:::::
+
+Of course, if you have a rendered lesson, another important thing is to check to
+make sure the outputs continue to work. If you notice any new errors or warnings
+new in the diff, you can work with the contributor to resolve them.
+
+::::: discussion
+
+### Risk Management
+
+Accepting generated content into lessons from anyone runs the risk of a security
+breach by exposing secrets. To mitigate this risk, GitHub limits the scope of
+what is possible inside a pull request so that we can check and render the
+content without risk of exploitation. Through this, we render and check the
+lesson inside the pull request with no privileges, check that the pull request
+is valid (not malicious), and then create a temporary branch for an exploratory
+preview, allowing the maintainer to audit the generated content before it gets
+adopted into the curriculum.
+
+If the PR is invalid (e.g. the contributor spoofed a separate, valid PR, or
+modified one of the github actions files), then the maintainer is alerted that
+the PR is potentially risky (see the [Being Vigilant](#being-vigilant) section
+for details)
+
+![The pull request cycle. Ellipse nodes (Pull Request and Maintainer Review)
+are the only places that require maintainer
+attention.](https://raw.githubusercontent.com/zkamvar/stunning-barnacle/main/img/pr-flow.dot.svg){alt="Workflow
+diagram from a pull request starting from Pull Request, and going to a path
+involving validation, artifact creation, maintainer review, and potential
+deployment."}
+
+:::::
+
+## Automated Pull Requests
+
+There are two situations where you would receive a pull request from [The
+Carpentries Apprentice bot](https://github.com/znk-machine/)
+
+1. The workflows need to be updated to the latest versions
+2. You have a lesson that uses generated content, the software requirements file
+ (e.g. renv.lock or [future] requirements.txt) is updated to the latest
+ versions and the lesson is re-built.
+
+More details about the purpose of these builds can be found in [The Chapter on
+updating lesson components](update.md).
+
+::: callout
+
+### For Lessons Outside of The Carpentries
+
+If you are using {sandpaper} to work on a lesson on your own personal account,
+these pull requests may never trigger. If you want them to work, follow the
+instructions in the technical article in {sandpaper} called [Working with
+Automated Pull Requests].
+
+:::
+
+
+### Workflow Updates
+
+When you receive a workflow update pull request, it will be on a branch called
+`update/workflows`, state that it is a bot and then indicate which version of
+sandpaper the workflows will be updated to.
+
+![](fig/pr-apprentice-workflow.png){alt="Screen shot of the bot commenting that
+it is an automated build and that it is updating workflows."}
+
+Because this PR contains changed workflow files, it will be marked as invalid
+no preview will be created, rendering a comment that indicates as such.
+
+![A Pull Request from [@carpentries-bot](https://github.com/carpentries-bot)
+signalling that workflows are modified and that they can be merged if you trust
+the bot](fig/pr-bot-workflow.png){alt="Screen shot of the github-actions bot
+commenting with the heading 'Modified Workflows' with text 'Pull Request
+contains modified workflows and no preview will be created.' It lists the
+workflow files modified and then says in bold text: 'If this is not from a
+trusted source, please inspect the changes for any malicious content.'"}
+
+### Updating Package Cache
+
+Updates to the package cache are on the `updates/packages` branch and
+accompanied by a bot comment that indicates the package versions that have been
+updated.
+
+![A Pull Request from [@carpentries-bot](https://github.com/carpentries-bot)
+giving details of what packages were modified and that they can be merged if you
+trust the bot](fig/pr-apprentice-cache.png){alt="Screen shot of the apprentice
+bot commenting that package versions have been updated in the lesson (e.g. xfun
+version changing from 0.33 to 0.34). It indicates that a comment will appear in
+a few minutes to show what has changed."}
+
+You will notice at the bottom of the comment there are instructions for how to
+check out a new branch and inspect the changes locally:
+
+```bash
+git fetch origin update/packages
+git checkout update/packages
+```
+
+You are free to push code changes to this branch to update any lesson material
+that has changed due to package updates or you can also pin the versions of the
+packages you do not want updated.
+
+#### Status Updates
+
+When the pull request comes in from [The Carpentries Apprentice], you will see
+this comment immediately:
+
+![A sign that good things will come](fig/pr-bot-comment-ok.png){alt="a comment
+from github actions (bot) that with the heading 'Pre-Flight Checkes Passed' and
+a smiley face. The text reads 'This pull request has been checked and contains
+no modified workflow files, spoofing, or invalid commits. Results of any
+additional workflows will appear here when they are done.'"}
+
+In the next couple of minutes, the R Markdown files will be re-built with the
+updated versions of the packages and the comment will update to reveal changes
+that have been made (if any).
+
+## Being Vigilant
+
+### Preventing Malicious Commits
+
+The pull request previews are designed to allow you to inspect the potential
+changes before they go live. Because our lessons run arbitrary code, it is
+important to inspect the changes to make sure that someone is not trying to
+insert anything malicious into your lesson. A good rule of thumb for maintaining
+your lesson is that if there are changes are changes you do not understand
+coming from someone other than @carpentries-bot, then, it's a good idea to wait
+to merge until you can fully understand the changes that are being proposed.
+
+One risk that might happen is if someone updates lesson content and the github
+workflows at the same time. If this happens, you will see a comment from the
+workflows that looks like this:
+
+
+![A warning that something is not quite
+right](fig/pr-bot-comment-warn.png){alt="a comment from github actions (bot)
+with the heading 'WARNING' flanked by yellow warning symbols. The text reads
+'This pull request contains a mix of workflow files and regular files. This
+could be malicious.' The list of regular files are episodes/introduction.Rmd and
+episodes/files/malicious-script.sh. The list of workflow files shows
+.github/workflows/sandpaper-main.yaml"}
+
+It is not always the case that changes in lesson files and workflow files will
+be bad, but it is not good practice to mix them.
+
+
+### Transition from carpentries/styles
+
+During the migration to The Carpentries Workbench, we are using [the lesson
+transition tool](https://github.com/carpentries/lesson-transition#readme) to
+convert lessons from the former "lesson template" to The Workbench. This
+involved removing commits unrelated to lesson content from the git history,
+which reduces the size of the lesson's git repository and has the benefit of
+making the contribution log more clear. The downside is that forks that were
+created before the lesson was transferred to The Workbench suddenly became
+invalid.
+
+If someone attempts to merge a pull request from an old repository, the first
+thing you will notice is hundreds of new commits and the second thing you will
+notice is the results of the automated check
+
+![A warning that something is not quite
+right](fig/pr-bot-comment-danger.png){alt="a comment from github actions (bot)
+with the heading 'DANGER' flanked by red 'x' symbols. The text reads
+in bold letters 'DO NOT MERGE THIS PULL REQUEST' and gives information about
+the divergent history and the invalid commit. It has extra information for the
+pull request author to delete their fork and re-fork the repository to
+contribute changes."}
+
+
+
+:::::::::::::::::::::::::::::: keypoints
+
+- Pull requests for generated formats requires validate of prose and generated content
+- Inspecting the rendered markdown output can help maintainers identify changes that occur due to software before they are deployed to the website
+- Automated pull requests help keep the infrastructure up-to-date
+
+::::::::::::::::::::::::::::::::::::::::
diff --git a/reference.md b/reference.md
new file mode 100644
index 00000000..1f116025
--- /dev/null
+++ b/reference.md
@@ -0,0 +1,20 @@
+---
+title: Learner Reference
+---
+
+## Glossary
+
+sandpaper
+: An R package from The Carpentries that is the main user interface for The
+ Carpentries Workbench. More information at:
+ https://carpentries.github.io/sandpaper
+
+varnish
+: An R package from The Carpentries that provides the HTML templates, CSS, and
+ JavaScript code for lesson websites generated via The Carpentries Workbench.
+ More information at: https://carpentries.github.io/varnish
+
+pegboard
+: An R package from The Carpentries that provides parsing and validation of
+ markdown source materials for The Carpentries Workbench. More information at:
+ https://carpentries.github.io/pegboard
diff --git a/renv.lock b/renv.lock
new file mode 100644
index 00000000..447cc908
--- /dev/null
+++ b/renv.lock
@@ -0,0 +1,342 @@
+{
+ "R": {
+ "Version": "4.4.1",
+ "Repositories": [
+ {
+ "Name": "carpentries",
+ "URL": "https://carpentries.r-universe.dev"
+ },
+ {
+ "Name": "carpentries_archive",
+ "URL": "https://carpentries.github.io/drat"
+ },
+ {
+ "Name": "CRAN",
+ "URL": "https://cran.rstudio.com"
+ }
+ ]
+ },
+ "Packages": {
+ "R6": {
+ "Package": "R6",
+ "Version": "2.5.1",
+ "Source": "Repository",
+ "Repository": "RSPM",
+ "Requirements": [
+ "R"
+ ],
+ "Hash": "470851b6d5d0ac559e9d01bb352b4021"
+ },
+ "base64enc": {
+ "Package": "base64enc",
+ "Version": "0.1-3",
+ "Source": "Repository",
+ "Repository": "RSPM",
+ "Requirements": [
+ "R"
+ ],
+ "Hash": "543776ae6848fde2f48ff3816d0628bc"
+ },
+ "bslib": {
+ "Package": "bslib",
+ "Version": "0.8.0",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "base64enc",
+ "cachem",
+ "fastmap",
+ "grDevices",
+ "htmltools",
+ "jquerylib",
+ "jsonlite",
+ "lifecycle",
+ "memoise",
+ "mime",
+ "rlang",
+ "sass"
+ ],
+ "Hash": "b299c6741ca9746fb227debcb0f9fb6c"
+ },
+ "cachem": {
+ "Package": "cachem",
+ "Version": "1.1.0",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "fastmap",
+ "rlang"
+ ],
+ "Hash": "cd9a672193789068eb5a2aad65a0dedf"
+ },
+ "cli": {
+ "Package": "cli",
+ "Version": "3.6.3",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "utils"
+ ],
+ "Hash": "b21916dd77a27642b447374a5d30ecf3"
+ },
+ "digest": {
+ "Package": "digest",
+ "Version": "0.6.37",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "utils"
+ ],
+ "Hash": "33698c4b3127fc9f506654607fb73676"
+ },
+ "evaluate": {
+ "Package": "evaluate",
+ "Version": "1.0.0",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R"
+ ],
+ "Hash": "6b567375113ceb7d9f800de4dd42218e"
+ },
+ "fastmap": {
+ "Package": "fastmap",
+ "Version": "1.2.0",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Hash": "aa5e1cd11c2d15497494c5292d7ffcc8"
+ },
+ "fontawesome": {
+ "Package": "fontawesome",
+ "Version": "0.5.2",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "htmltools",
+ "rlang"
+ ],
+ "Hash": "c2efdd5f0bcd1ea861c2d4e2a883a67d"
+ },
+ "fs": {
+ "Package": "fs",
+ "Version": "1.6.4",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "methods"
+ ],
+ "Hash": "15aeb8c27f5ea5161f9f6a641fafd93a"
+ },
+ "glue": {
+ "Package": "glue",
+ "Version": "1.8.0",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "methods"
+ ],
+ "Hash": "5899f1eaa825580172bb56c08266f37c"
+ },
+ "highr": {
+ "Package": "highr",
+ "Version": "0.11",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "xfun"
+ ],
+ "Hash": "d65ba49117ca223614f71b60d85b8ab7"
+ },
+ "htmltools": {
+ "Package": "htmltools",
+ "Version": "0.5.8.1",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "base64enc",
+ "digest",
+ "fastmap",
+ "grDevices",
+ "rlang",
+ "utils"
+ ],
+ "Hash": "81d371a9cc60640e74e4ab6ac46dcedc"
+ },
+ "jquerylib": {
+ "Package": "jquerylib",
+ "Version": "0.1.4",
+ "Source": "Repository",
+ "Repository": "RSPM",
+ "Requirements": [
+ "htmltools"
+ ],
+ "Hash": "5aab57a3bd297eee1c1d862735972182"
+ },
+ "jsonlite": {
+ "Package": "jsonlite",
+ "Version": "1.8.9",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "methods"
+ ],
+ "Hash": "4e993b65c2c3ffbffce7bb3e2c6f832b"
+ },
+ "knitr": {
+ "Package": "knitr",
+ "Version": "1.48",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "evaluate",
+ "highr",
+ "methods",
+ "tools",
+ "xfun",
+ "yaml"
+ ],
+ "Hash": "acf380f300c721da9fde7df115a5f86f"
+ },
+ "lifecycle": {
+ "Package": "lifecycle",
+ "Version": "1.0.4",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "cli",
+ "glue",
+ "rlang"
+ ],
+ "Hash": "b8552d117e1b808b09a832f589b79035"
+ },
+ "memoise": {
+ "Package": "memoise",
+ "Version": "2.0.1",
+ "Source": "Repository",
+ "Repository": "RSPM",
+ "Requirements": [
+ "cachem",
+ "rlang"
+ ],
+ "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c"
+ },
+ "mime": {
+ "Package": "mime",
+ "Version": "0.12",
+ "Source": "Repository",
+ "Repository": "RSPM",
+ "Requirements": [
+ "tools"
+ ],
+ "Hash": "18e9c28c1d3ca1560ce30658b22ce104"
+ },
+ "rappdirs": {
+ "Package": "rappdirs",
+ "Version": "0.3.3",
+ "Source": "Repository",
+ "Repository": "RSPM",
+ "Requirements": [
+ "R"
+ ],
+ "Hash": "5e3c5dc0b071b21fa128676560dbe94d"
+ },
+ "renv": {
+ "Package": "renv",
+ "Version": "1.0.9",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "utils"
+ ],
+ "Hash": "ef233f0e9064fc88c898b340c9add5c2"
+ },
+ "rlang": {
+ "Package": "rlang",
+ "Version": "1.1.4",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "utils"
+ ],
+ "Hash": "3eec01f8b1dee337674b2e34ab1f9bc1"
+ },
+ "rmarkdown": {
+ "Package": "rmarkdown",
+ "Version": "2.28",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "bslib",
+ "evaluate",
+ "fontawesome",
+ "htmltools",
+ "jquerylib",
+ "jsonlite",
+ "knitr",
+ "methods",
+ "tinytex",
+ "tools",
+ "utils",
+ "xfun",
+ "yaml"
+ ],
+ "Hash": "062470668513dcda416927085ee9bdc7"
+ },
+ "sass": {
+ "Package": "sass",
+ "Version": "0.4.9",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R6",
+ "fs",
+ "htmltools",
+ "rappdirs",
+ "rlang"
+ ],
+ "Hash": "d53dbfddf695303ea4ad66f86e99b95d"
+ },
+ "tinytex": {
+ "Package": "tinytex",
+ "Version": "0.53",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "xfun"
+ ],
+ "Hash": "9db859e8aabbb474293dde3097839420"
+ },
+ "xfun": {
+ "Package": "xfun",
+ "Version": "0.47",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Requirements": [
+ "R",
+ "grDevices",
+ "stats",
+ "tools"
+ ],
+ "Hash": "36ab21660e2d095fef0d83f689e0477c"
+ },
+ "yaml": {
+ "Package": "yaml",
+ "Version": "2.3.10",
+ "Source": "Repository",
+ "Repository": "CRAN",
+ "Hash": "51dab85c6c98e50a18d7551e9d49f76c"
+ }
+ }
+}
diff --git a/setup.md b/setup.md
new file mode 100644
index 00000000..6119d6e7
--- /dev/null
+++ b/setup.md
@@ -0,0 +1,752 @@
+---
+title: Setup
+---
+
+## Overview
+
+The lesson infrastructure is built on Git, the R language, and pandoc. It consists of
+four components:
+
+1. The source content (plain markdown or RMarkdown files organized into folders
+ with a configuration yaml file)
+2. The engine (R package [{sandpaper}])to orchestrate building the content from
+ markdown to HTML
+3. The validator (R package [{pegboard}]) to parse the source files and
+ highlight common errors
+4. The style (R package [{varnish}]) HTML, CSS, and JavaScript styling elements
+ for the final website
+
+Details of how these tools work together are explained in the [Lesson
+Deployment chapter](../episodes/deployment.md). In short, you can expect to
+interact with the source content and {sandpaper} to author and preview your
+lesson.
+
+### Required Software {#required}
+
+This setup document will walk you through the process of installing or upgrading
+the required software in the following order.
+
+1. **[Git]** (≥ 2.28 recommended)
+2. **[R]** (≥ 4.x)
+3. **[pandoc]** (≥ 3.x)
+4. The lesson infrastructure R packages
+ i. **[{sandpaper}]** (development version)
+ ii. **[{varnish}]** (development version)
+ iii. **[{pegboard}]** (development version)
+ iiii. **[{tinkr}]** (markdown parser required by {pegboard})
+
+ Once you have Git, R, and Pandoc installed, these packages can be installed
+ and updated via:
+ ```r
+ install.packages(c("sandpaper", "varnish", "pegboard"),
+ repos = c("https://carpentries.r-universe.dev/", getOption("repos")))
+ ```
+
+### Recommended Software {#recommend}
+
+If you are using R or pandoc for the first time, we recommend using [the RStudio
+IDE][RStudio] for the following reasons:
+
+1. It comes with [pandoc] pre-installed.
+2. It works consistently across all major platforms.
+3. It provides a dedicated BASH console so you can easily switch between R and Git
+ operations.
+4. There are convenient keyboard shortcuts to preview lessons.
+5. On Windows, it will automatically detect your R installation without you
+ needing to edit your `PATH`.
+
+If you do not want to use RStudio, that's perfectly okay and expected! We want
+to be able to meet you where you are to work with the new template. If you feel
+comfortable using a different tool (e.g. the command line or VSCode), then you
+should install R and pandoc separately and make sure that they are in your path.
+
+
+### Installation
+
+This will guide you through installing the foundational software and
+infrastructure packages on your computer. If you already have software
+installed and are curious if you should update it to a newer version, the answer
+is almost always, yes, update to a newer version, because often the newer
+versions will contain important bug fixes that are important to the secruity of
+your computer.
+
+Jump to the installation instructions for your system: [Windows](#windows),
+[MacOS](#mac), or [Linux](#linux)
+
+## Installing on Windows {#windows}
+
+### Git
+
+We recommend installing git via the [Git for Windows installer](https://gitforwindows.org/). The installer is going to ask a lot of questions,
+so we recommend [using The Carpentries instructions for workshop
+participants](https://carpentries.github.io/workshop-template/#the-bash-shell).
+
+#### Test your installation
+
+To test that you have git installed, open your command line by pressing Windows+R
+and type `cmd` to bring up the command prompt. From there, you
+can type `git --version` to see the version of your git installation. You might
+see something like this:
+
+```bash
+git --version
+```
+
+```output
+git version 2.31.1.windows.1
+```
+
+If, however, you see this error, then you should try to install git again.
+
+```error
+'git' is not recognised as an internal or external command,
+operable program or batch file.
+```
+
+
+### R
+
+Install the [latest version of R for Windows](https://cran.r-project.org/bin/windows/base/). There is also a video tutorial
+up on [The Carpentries instructions for workshop
+participants](https://carpentries.github.io/workshop-template/#r-1)
+that can be quite helpful for parsing the steps of installing R on Windows.
+
+::::::::::::::::::::: callout
+
+#### Optional: Want to add R to your PATH? {#winpath}
+
+As we mention above, [we recommend using RStudio for your lesson](#recommend),
+but if you want to be able to integrate the lesson infrastructure into your own
+preferred workflow, you need to have R on your path. The catch is that R for
+Windows does not automatically set your `PATH` variable.
+
+[Here are some instructions on setting up your PATH on Windows using both the
+GUI and CLI](https://www.maketecheasier.com/what-is-the-windows-path/). Note
+that R will normally install at something like
+`c:\Program Files\R\R-4.1.0\bin\x64`, but if you are not admin, it will install
+in your Documents folder.
+
+To verify that R is installed in your `PATH`, open your command line by pressing
+Windows+R
+and type `cmd` to bring up the command prompt. From there,
+you can type `R --version` at the prompt. Your output should be similar to below,
+with a version β₯ 4.x.
+
+```bash
+R --version
+```
+```output
+R version 4.1.0 (2021-05-18) -- "Camp Pontanezen"
+Copyright (C) 2021 The R Foundation for Statistical Computing
+Platform: x86_64-mingw32/x64 (64-bit)
+
+R is free software and comes with ABSOLUTELY NO WARRANTY.
+You are welcome to redistribute it under the terms of the
+GNU General Public License versions 2 or 3.
+For more information about these matters see
+https://www.gnu.org/licenses/.
+```
+
+:::::::::::::::::::::::::::::
+
+### pandoc
+
+There are two ways to install pandoc:
+
+#### Via RStudio (recommended)
+
+Since pandoc comes bundled with RStudio, you can install it by installing the
+latest version of RStudio. You can [download the installer from the RStudio
+website][RStudio].
+
+#### Via the pandoc website
+
+If you are comfortable adding R to your windows PATH (see [previous
+section](#winpath)), then you can install pandoc by using the binary provided on
+its website at
+
+#### Test your installation
+
+We will wait to test the pandoc installation after we install the
+infrastructure packages, to make sure it's discoverable by R.
+
+### Infrastructure R packages
+
+To install the R packages, you will need to **open RStudio** (or start R from
+the command line if you did not install RStudio) and enter the following lines
+into the console.
+
+```r
+# register the repositories for The Carpentries and CRAN
+options(repos = c(
+ carpentries = "https://carpentries.r-universe.dev/",
+ CRAN = "https://cran.rstudio.com/"
+))
+
+# Install the template packages to your R library
+install.packages(c("sandpaper", "varnish", "pegboard"))
+```
+
+## Installing on MacOS {#mac}
+
+
+
+### Git
+
+You should have git pre-installed on your macOS, but it is likely that this is
+an old version. We recommend installing [The latest version of Git for MacOS](https://git-scm.com/downloads/mac).
+For a video guide, you can look at
+the [instructions for workshop
+participants](https://carpentries.github.io/workshop-template/#git-1).
+
+#### Test your installation
+
+To test your installation of Git and confirm it works, open **Terminal.app** and
+type the following:
+
+```bash
+git --version
+```
+
+```output
+git version 2.31.0
+```
+
+If you have the default version of git, you might see this output, and that's
+okay for the purposes of this template.
+
+```output
+git version 2.24.3 (Apple Git-128)
+```
+
+### R
+
+::: prereq
+
+### Homebrew Not Recommended
+
+Installing R via Homebrew can allow you to customise your installation, but you
+lose the advantage of having readily available package binaries. Moreover, if
+you do not have the required C libraries (e.g. `libxslt`) installed, then the
+installation of some packages will fail. So, unless you are prepared for this,
+please do not use Homebrew to install R.
+
+:::
+
+
+You can install the [latest R release][R] for MacOS from
+. There is also a video tutorial
+up on [The Carpentries instructions for workshop
+participants](https://carpentries.github.io/workshop-template/#rstats-macos)
+that can be quite helpful for parsing the steps of installing R on MacOS.
+
+#### Test your installation
+
+You can test your installation of R by opening **Terminal.app** and typing `R
+--version` into the prompt. Your output should be similar to below,
+with a version β₯ 4.x.
+
+```bash
+R --version
+```
+```output
+R version 4.1.0 (2021-05-18) -- "Camp Pontanezen"
+Copyright (C) 2021 The R Foundation for Statistical Computing
+Platform: x86_64-apple-darwin17.0 (64-bit)
+
+R is free software and comes with ABSOLUTELY NO WARRANTY.
+You are welcome to redistribute it under the terms of the
+GNU General Public License versions 2 or 3.
+For more information about these matters see
+https://www.gnu.org/licenses/.
+```
+
+### pandoc
+
+There are two ways to install pandoc:
+
+#### Via RStudio (recommended)
+
+Since pandoc comes bundled with RStudio, you can install it by installing the
+latest version of RStudio. You can [download the installer from the RStudio
+website][RStudio]. RStudio will be a `*.dmg` (disk image) that you will
+double click to open a window that will look something like this:
+
+![](fig/rstudio-mac-install.png){alt="Installation window for RStudio on mac
+showing two items on a plain background: the Applications folder on the left and
+the RStudio icon on the right."}
+
+You should *drag the RStudio icon to the left, **into** the Applications folder*
+to install RStudio on your computer.
+
+#### Via the pandoc website
+
+If are more comfortable using R from the command line, then you can [install
+pandoc](https://pandoc.org/installing.html) by clicking the "Download the latest
+installer for macOS" button. This will save a file called
+`pandoc-X.XX-macOS.pkg` installer to your computer. Open the installer and
+follow the instructions to install pandoc on your computer.
+
+#### Test your installation
+
+We will wait to test the pandoc installation after we install the
+infrastructure packages, to make sure it's discoverable by R.
+
+### Infrastructure R packages
+
+To install the R packages, you will need to **open RStudio** (or start R from
+the command line if you did not install RStudio) and enter the following lines
+into the console.
+
+```r
+# register the repositories for The Carpentries and CRAN
+options(repos = c(
+ carpentries = "https://carpentries.r-universe.dev/",
+ CRAN = "https://cran.rstudio.com/"
+))
+
+# Install the template packages to your R library
+install.packages(c("sandpaper", "varnish", "pegboard"))
+```
+
+## Installing on Linux {#linux}
+
+A lot of the documentation for Linux is nuanced because it assumes that if you
+use Linux, then you automatically know how to install things by the command
+line. I will be providing instructions as best I can for Ubuntu Linux and point
+to resourced for other distributions. For Ubuntu/Debian, the default `apt`
+repository is often out of date, so you will need to use a
+[Personal Package Archive aka PPA](https://itsfoss.com/ppa-guide/) to install
+the latest version of a particular software, which I will include in these
+instructions.
+
+### Git
+
+You should have git pre-installed on your computer, but it will likely be
+outdated. It's okay if this is the case, but if you want to update via `apt`,
+you can add the git-core ppa:
+
+```bash
+sudo add-apt-repository ppa:git-core/ppa
+sudo apt update
+sudo apt install git
+```
+
+#### Test your installation
+
+Test your git installation by opening the terminal and running
+
+```bash
+git --version
+```
+```output
+git version 2.31.1
+```
+
+### R
+
+To install R, you can visit to check if
+your platform is supported. For Ubuntu, there are detailed instructions at:
+. Here are the commands to register
+the PPA on your machine and then install R:
+
+```bash
+# update indices
+sudo apt update -qq
+# install two helper packages we need
+sudo apt install --no-install-recommends software-properties-common dirmngr
+# import the signing key (by Michael Rutter) for these repo
+sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9
+# add the R 4.0 repo from CRAN -- adjust 'focal' to 'groovy' or 'bionic' as needed
+sudo add-apt-repository "deb https://cloud.r-project.org/bin/linux/ubuntu $(lsb_release -cs)-cran40/"
+
+# Install R
+sudo apt install --no-install-recommends r-base
+```
+
+#### Test your installation
+
+Test your R installation by opening your terminal and running
+`R --version` into the prompt. Your output should be similar to below,
+with a version β₯ 4.x.
+
+```bash
+R --version
+```
+
+```output
+R version 4.1.0 (2021-05-18) -- "Camp Pontanezen"
+Copyright (C) 2021 The R Foundation for Statistical Computing
+Platform: x86_64-pc-linux-gnu (64-bit)
+
+R is free software and comes with ABSOLUTELY NO WARRANTY.
+You are welcome to redistribute it under the terms of the
+GNU General Public License versions 2 or 3.
+For more information about these matters see
+https://www.gnu.org/licenses/.
+
+```
+
+### pandoc
+
+There are two ways to install pandoc:
+
+#### Via RStudio (recommended)
+
+Since pandoc comes bundled with RStudio, you can install it by installing the
+latest version of RStudio. You can [download the installer from the RStudio
+website][RStudio]. When installing RStudio for Linux, your distribution may not
+be shown on the landing page (e.g. Ubuntu 20.04). In this case, choose the most
+recent version and download it to your Downloads folder or install it directly.
+
+::::::::::: callout
+
+##### Optional: verify the install
+
+You can optionally verify the download before installing by following the
+instructions at .
+
+:::::::::::::::::::
+
+
+#### Via the pandoc website
+
+If are more comfortable using R from the command line, then you can install
+pandoc by clicking the "Download the latest installer" button at
+. This will bring you to the release page
+on GitHub with a list of installers, and you should choose one of the ones that
+says "linux" according to what chip architecture you have (AMD vs ARM).
+
+#### Test your installation
+
+We will wait to test the pandoc installation after we install the
+infrastructure packages, to make sure it's discoverable by R.
+
+### Infrastructure R packages
+
+Linux packages normally need to be compiled by your system, which can take a
+long time the first time it happens. RStudio provides a package manager that
+pre-compiles Linux binaries. Note that you do not have to be using RStudio to
+take advantage of these binaries. The one we are using is set up for Ubuntu
+20.04 (focal).
+
+::::: callout
+
+#### Dependencies of Dependencies
+
+If you are not used to installing software on Linux, it can be frustrating
+sometimes because few things ever "just work" when you try to install them. The
+same is true for some R packages with compiled code.
+
+Some packages require underlying C libraries (e.g. the xml2 library), which are
+catalogued for Ubuntu in [The Carpentries R
+Universe](https://carpentries.r-universe.dev/ui#builds) and [available via the
+API](https://carpentries.r-universe.dev/ui#api). If you want to view the
+packages that are required (some of which may already be on your system), you
+can use `curl` and `jq` to produce a list:
+
+```bash
+curl https://carpentries.r-universe.dev/stats/sysdeps 2> /dev/null | jq -r '.headers[0] | select(. != null)'
+```
+
+This list can be sent to `apt-get install` to install everything:
+
+```bash
+sudo apt-get install -y \
+ $(curl https://carpentries.r-universe.dev/stats/sysdeps 2> /dev/null | jq -r '.headers[0] | select(. != null)') 2> /dev/null \
+ || echo "Not on Ubuntu"
+```
+
+After you have these installed, you will be able to install the required R
+packages without error.
+
+:::::
+
+:::: callout
+
+#### What if I have a different version of Linux?
+
+
+For the dependencies above, you can browse the [rstudio/r-system-requirements
+repository](https://github.com/rstudio/r-system-requirements) to find the
+correct formulation for your computer.
+
+In addition, you should check [the supported operating systems for the Posit
+Package
+Manager](https://packagemanager.posit.co/__docs__/admin/serving-binaries/#supported-operating-systems)
+to see if you will benefit from pre-built binaries.
+
+
+::::
+
+To install the R packages, you will need to **open RStudio** (or start R from
+the command line if you did not install RStudio) and enter the following lines
+into the console.
+
+```r
+# Set the default HTTP user agent to get pre-built binary packages
+RV <- getRversion()
+OS <- paste(RV, R.version["platform"], R.version["arch"], R.version["os"])
+codename <- sub("Codename.\t", "", system2("lsb_release", "-c", stdout = TRUE))
+options(HTTPUserAgent = sprintf("R/%s R (%s)", RV, OS))
+
+# register the repositories for The Carpentries and CRAN
+options(repos = c(
+ carpentries = "https://carpentries.r-universe.dev/",
+ CRAN = paste0("https://packagemanager.posit.co/all/__linux__/", codename, "/latest")
+))
+
+# Install the template packages to your R library
+install.packages(c("sandpaper", "varnish", "pegboard"))
+```
+
+::::::::::::: discussion
+
+#### Saving these settings for later
+
+Having binary packages for Linux was a game changer when they appeared and it's
+a good idea to have the above code run every time you start R so that you can
+take advantage of them. Add the code below to your `~/.Rprofile`.
+
+::::::::::::::::::::::::
+
+:::::: solution
+
+#### Add this to `~/.Rprofile`
+
+```r
+local({
+ # Set the default HTTP user agent to get pre-built binary packages
+ RV <- getRversion()
+ OS <- paste(RV, R.version["platform"], R.version["arch"], R.version["os"])
+ codename <- sub("Codename.\t", "", system2("lsb_release", "-c", stdout = TRUE))
+ options(HTTPUserAgent = sprintf("R/%s R (%s)", RV, OS))
+
+ # register the repositories for The Carpentries and CRAN
+ options(repos = c(
+ carpentries = "https://carpentries.r-universe.dev/",
+ CRAN = paste0("https://packagemanager.posit.co/all/__linux__/", codename, "/latest")
+ ))
+})
+```
+:::::::::::::::
+
+
+::::::::::::: callout
+
+#### What if I get errors installing packages?
+
+If you run into errors (non-zero exit status), it probably means that you were
+missing a C library dependency that needs to be installed via your package
+manager (i.e. apt). To resolve these issues, scroll back in the log and you
+might find messages that looks similar to this:
+
+```output
+* installing *source* package βxsltβ ...
+** using staged installation
+Package libexslt was not found in the pkg-config search path.
+Perhaps you should add the directory containing `libexslt.pc'
+to the PKG_CONFIG_PATH environment variable
+No package 'libexslt' found
+Using PKG_CFLAGS=-I/usr/include/libxml2
+Using PKG_LIBS=-lexslt -lxslt -lxml2
+-----------------------------[ ANTICONF ]-------------------------------
+Configuration failed to find libexslt library. Try installing:
+ * deb: libxslt1-dev (Debian, Ubuntu, etc)
+ * rpm: libxslt-devel (Fedora, CentOS, RHEL)
+ * csw: libxslt_dev (Solaris)
+If libexslt is already installed, check that 'pkg-config' is in your
+PATH and PKG_CONFIG_PATH contains a libexslt.pc file. If pkg-config
+is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:
+R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'
+---------------------------[ ERROR MESSAGE ]----------------------------
+:1:10: fatal error: libxslt/xslt.h: No such file or directory
+compilation terminated.
+------------------------------------------------------------------------
+```
+
+Use the instructions in these logs to install the correct package from your
+terminal and then open R or RStudio and retry installing the packages.
+
+:::::::::::::::::::::
+
+## Test your installation {#install-test}
+
+Now that you have installed the lesson components, it is a good idea to run a
+small test to verify that these components work together. To test your
+installation **open RStudio** (or launch R if you have not installed RStudio)
+and enter the following commands to confirm everything works
+
+```r
+rmarkdown::pandoc_version()
+tmp <- tempfile()
+sandpaper::no_package_cache()
+sandpaper::create_lesson(tmp, open = FALSE)
+sandpaper::build_lesson(tmp, preview = FALSE, quiet = TRUE)
+fs::dir_tree(tmp, recurse = 1)
+```
+
+```output
+[1] '2.19.2'
+βΉ Consent for package cache revoked. Use `use_package_cache()` to undo.
+β Creating Lesson in '/tmp/RtmpnRjHyr/file12f34734be05f'...
+β First episode created in '/tmp/RtmpnRjHyr/file12f34734be05f/episodes/01-introduction.Rmd'
+βΉ Workflows up-to-date!
+β Lesson successfully created in '/tmp/RtmpnRjHyr/file12f34734be05f'
+/tmp/RtmpnRjHyr/file12f34734be05f
+βββ CODE_OF_CONDUCT.md
+βββ CONTRIBUTING.md
+βββ LICENSE.md
+βββ README.md
+βββ config.yaml
+βββ episodes
+β βββ 01-introduction.Rmd
+β βββ data
+β βββ fig
+β βββ files
+βββ index.md
+βββ instructors
+β βββ instructor-notes.md
+βββ learners
+β βββ setup.md
+βββ profiles
+β βββ learner-profiles.md
+βββ site
+ βββ DESCRIPTION
+ βββ README.md
+ βββ _pkgdown.yaml
+ βββ built
+ βββ docs
+```
+
+If the installation did not work, please [raise an issue on
+GitHub](https://github.com/carpentries/sandpaper-docs/issues/new) and I can help
+troubleshoot.
+
+## Installation FAQ
+
+### Why does it take 5 lines of code to install the infrastructure?
+
+In the future, this will be ONE line of code!
+
+Since we are currently in the alpha phase of testing, the infrastructure can
+update at any moment. Normally, packages will come from
+[CRAN](https://glosario.carpentries.org/en/#cran), but our development packages
+are not yet on CRAN, so the are stored in The Carpentries and rOpenSci
+development repositories.
+
+### Do I really need to use RStudio?
+
+No. We recommend using RStudio for [several reasons that pertain to ease of
+use and standardisation across systems](#recommend), but we do not absolutely
+require it. If you are able to get Git, R, and pandoc installed on your system,
+then you do not need to use RStudio.
+
+### What is an R Library?
+
+An R library is a folder on your computer that stores R packages. When you
+install R packages, the first message you will see will probably be something
+like (on Windows):
+
+```
+Installing packages into βc:/Users/USER/Documents/R/win-library/4.0β
+(as βlibβ is unspecified)
+```
+
+This folder is where all of the R packages you install via `install.packages()`
+will live. If you ever need to look this up, you can use the `.libPaths()`
+function.
+
+Sometimes, your R session will issue a warning that says a folder is not
+writeable and asks if you would like to use a personal library instead. In this
+case, select "yes".
+
+## Using the lesson engine
+
+Throughout the lesson, I will ask you to **open R or RStudio**. If you are using
+RStudio, you can open it by double-clicking on the RStudio icon in your
+application launcher; you do not have to open R separately to use RStudio.
+
+If you are using R, you can open it in your terminal application by typing `R`.
+Your prompt will be replaced by a `>`, which indicates that you are in R's
+interactive [REPL](https://glosario.carpentries.org/en/#repl).
+
+You can exit R or RStudio by typing `q()` in the R console.
+
+::::::::: prereq
+
+### Setting up your R workspace
+
+When you set up R, it's important to make sure you set it up to always start R
+with a clean slate[^workspace]: never save your workspace on exit and never
+load a previously saved workspace on startup.
+
+#### Via RStudio
+
+If you are using RStudio, you can [follow the instructions in this forum
+post](https://community.rstudio.com/t/first-line-of-every-r-script/799/12?u=zkamvar):
+
+1. From the menu, select Tools > Global Options
+2. Under **Workspace Options**, de-select "Restore .RData into workspace at
+ startup" and set "Save workspace to .RData on exit" to "Never"
+
+#### Via Command Line Interface
+
+The flags `--no-restore` and `--no-save` will set these defaults, so you can
+create an alias for R in the `.bashrc` file in your home directory:
+
+```bash
+alias R='R --no-restore --no-save'
+```
+
+::::::::::::::::::
+
+## Connect to GitHub
+
+You will need to make sure your git session is connected to GitHub. To do so,
+you will need to use an SSH or HTTPS protocol. If you already know how to push
+and pull from GitHub using the command line, you do not need to worry about
+setting this up.
+
+If you do not have this set up, you should [choose a protocol
+](https://docs.github.com/en/github/getting-started-with-github/about-remote-repositories)
+and then set them up according to the instructions from GitHub.
+
+:::::::::::::::: callout
+
+### Is GitHub's Documentation Confusing?
+
+If you are like me, you may find GitHub's documentation slightly confusing
+and/or lacking. I've found the following resources to be extremely helpful for
+setting up authentication credentials for your account:
+
+[Remotes in GitHub (Software Carpentry)](https://swcarpentry.github.io/git-novice/07-github)
+: A walkthrough of creating a repository on GitHub and pushing to it via the
+ command line.
+
+[Connect to GitHub (Happy Git With R)](https://happygitwithr.com/push-pull-github.html)
+: A walkthrough of creating a throwaway repository that gives you a good idea
+ for the mechanics of working with GitHub.
+
+[Cache credentials for HTTPS (Happy Git With R)](https://happygitwithr.com/credential-caching.html)
+: Clear explanation on how to set up a Personal Access Token and the benefits of
+ using HTTPS. This explains how to do this in both the shell and R.
+
+[Set up keys for SSH (Happy Git With R)](https://happygitwithr.com/ssh-keys.html)
+: Clear explanation on what SSH key pairs are and how to set up and connect them
+ with GitHub. This has recommendations using both the shell and RStudio.
+
+::::::::::::::::::::::::
+
+[Git]: https://git-scm.com/
+[R]: https://cran.rstudio.org/
+[pandoc]: https://pandoc.org/
+[{tinkr}]: https://docs.ropensci.org/tinkr/
+[RStudio]: https://rstudio.com/products/rstudio/download/#download
+[^workspace]: By default, R will ask if you want to save your workspace to a
+ hidden file called `.RData`. This is loaded when you start R, restoring your
+ environment with all of the packages and objects you had previously loaded.
+ This default behavior is not good for reproducibility and makes updating
+ packages very very difficult. In 2017 Jenny Bryan wrote a very good article
+ about the benefits of having a project-based workflow, starting from a clean
+ slate:
diff --git a/style.md b/style.md
new file mode 100644
index 00000000..385bc96a
--- /dev/null
+++ b/style.md
@@ -0,0 +1,150 @@
+---
+title: 'Style Guide'
+---
+
+A collection of guidelines to follow when writing
+source (R) Markdown files for use with {sandpaper}.
+The Carpentries also provides a [general Style Guide](https://docs.carpentries.org/topic_folders/communications/resources/style-guide.html)
+for written content e.g. blog posts, website and lesson content, etc.
+
+- [Fenced Divs](#fenced-divs)
+ - [Fence Length](#fence-length)
+ - [Whitespace](#whitespace)
+- [Figures](#figures)
+- [Line Length](#line-length)
+
+## Fenced Divs
+
+### Fence Length
+
+The following recommendations are made to improve legibility
+and make it easier to distinguish between blocks of content
+in source files.
+
+#### First-level fenced divs
+
+For increased legibility, we recommend an opening fence length of around 50 characters
+(half to two-thirds of the screen),
+with a single space between the last colon and the class keyword.
+The length of closing fences should match the length of the opening fence plus keyword,
+for example:
+
+```markdown
+:::::::::::::::::::::::::::::::::::::::::: callout
+
+### An example callout
+
+This callout was opened with a fence of 50 characters.
+The end of the closing fence aligns with
+the last character in the 'callout' keyword.
+
+::::::::::::::::::::::::::::::::::::::::::::::::::
+```
+
+#### Nested fenced divs (e.g. challenge solutions)
+
+Where fenced divs are nested,
+e.g. attaching a solution block to a challenge,
+we recommend making the inner fences noticably shorter
+than the outer fences, e.g. 25 characters (one quarter to one third of the screen).
+E.g.
+
+```markdown
+:::::::::::::::::::::::::::::::::::::::: challenge
+
+### An example challenge
+
+This challenge was opened with a fence of 50 characters.
+
+:::::::::::::::: solution
+
+The nested solution block was opened with 25 characters,
+to make it stand out from the challenge.
+
+:::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::::::::::::::::::::::::
+```
+
+#### Instructor Notes
+
+Content written into divs with the 'instructor' class will only appear
+in the Instructor View of the lesson website.
+To help distinguish these blocks from the rest of the page content,
+we recommend a longer fence length (80 characters) for 'instructor' blocks:
+
+```markdown
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: instructor
+
+## Stay hydrated
+
+Rememeber to pause and drink some water.
+
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+```
+
+### Whitespace
+
+For legibility and to avoid
+[potential formatting issues](https://github.com/carpentries/sandpaper/issues/355),
+empty lines should flank the fences of a fenced div, e.g.
+
+```markdown
+:::::::::::::::::::::::::::::::::::::::::: callout
+
+### Good: whitespace either side of the fences
+
+This will ensure Markdown content renders as intended.
+
+::::::::::::::::::::::::::::::::::::::::::::::::::
+
+:::::::::::::::::::::::::::::::::::::::::: callout
+### Not recommended
+Without empty lines flanking the opening and closing fences,
+this callout is more difficult to read
+and some Markdown content such as lists may not render as intended.
+::::::::::::::::::::::::::::::::::::::::::::::::::
+```
+
+## Figures
+
+We recommend splitting Markdown image elements across multiple lines,
+to enhance readability:
+
+```markdown
+![
+The text in these square brackets provides a caption to images in
+[the Markdown syntax of The Carpentries Workbench](https://carpentries.github.io/sandpaper-docs/example.html#figures).
+](path/to/figure.svg){
+alt='Alternative text descriptions are defined here'
+width='33%'
+}
+```
+
+![
+The text in these square brackets provides a caption to images in
+[the Markdown syntax of The Carpentries Workbench](https://carpentries.github.io/sandpaper-docs/example.html#figures).
+](https://placekitten.com/300/300){
+alt='A random picture of a cute kitten'
+width='33%'
+}
+
+Source Markdown for figures can be difficult to read when confined to a single line,
+especially if the image caption contains its own Markdown elements such as links.
+
+For comparison, here is the one-line equivalent to the example above:
+
+```markdown
+![The text in these square brackets provides a caption to images in [the Markdown syntax of The Carpentries Workbench](https://carpentries.github.io/sandpaper-docs/example.html#figures).](path/to/figure.svg){alt='Alternative text descriptions are defined here' width='33%'}
+```
+
+## Line Length
+
+We recommend the use of [_Semantic Line Breaks_][sembr]
+with a maximum line length of 100 characters.
+As detailed in the Semantic Line Breaks specification,
+
+> A line MAY exceed the maximum line length if necessary,
+> such as to accommodate hyperlinks, code elements, or other markup.
+
+[sembr]: https://sembr.org/
diff --git a/update.md b/update.md
new file mode 100644
index 00000000..f90854ab
--- /dev/null
+++ b/update.md
@@ -0,0 +1,170 @@
+---
+title: "Maintaining a Healthy Infrastructure"
+teaching: 10
+exercises: 2
+---
+
+:::::::::::::::::::::::::::::::::::::: questions
+
+- What are the four components of the lesson infrastructure?
+- What lesson components are auto-updated on GitHub?
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+::::::::::::::::::::::::::::::::::::: objectives
+
+- Identify components of the workbench needed for lesson structure, validation,
+ styling, and deployment
+- Understand how to update R packages
+- Understand how to update GitHub workflows
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+
+:::: callout
+
+#### :construction: Under Development
+
+This episode is still actively being developed
+
+::::
+
+## Introduction
+
+The Carpentries Lesson Infrastructure is designed to be cu
+
+## Maintainer Tools
+
+This is {sandpaper}! It takes your source files and generates the outputs!
+
+Update in R with:
+
+```r
+install.packages("sandpaper", repos = "https://carpentries.r-universe.dev")
+```
+
+
+## Validator
+
+
+This is {pegboard}! It runs behind the scenes in {sandpaper} to parse the source
+documents and validate things like headings, images, and cross-links. It also
+can extract elements like code and individual sections.
+
+Update in R with:
+
+```r
+install.packages("pegboard", repos = "https://carpentries.r-universe.dev")
+```
+
+## Styling
+
+This is {varnish}! This package contains all the HTML, JavaScript, and CSS to
+make your generated HTML look like a Carpentries Lesson!
+
+Update in R with:
+
+```r
+sandpaper::update_varnish()
+```
+
+
+## Deployment
+
+### Updating Your Deployment Workflows
+
+The workflows are the the only place in our lesson that needs to be kept
+up-to-date with upstream changes from [{sandpaper}]. While we try as much as
+possible to keep the functionality of [{sandpaper}] inside the package itself,
+there are times when we need to update the GitHub workflows for security or
+performance reasons. You can update your workflows in one of two ways: via
+GitHub or via [{sandpaper}].
+
+
+:::: callout
+
+#### :construction: Under Development
+
+Workflow updates are still underdevelopment, but **are available for use**. We
+are exploring different methods for making these unobtrusive as possible such as
+specifying scheduled updates via `config.yaml` and even creating a bot that will
+remove the need for this workflow.
+
+::::::::::::
+
+### On Schedule (default)
+
+The workflow update workflow is scheduled to run every Tuesday at 00:00 UTC. If
+there are any changes in the upstream workflows, then a Pull Request will be
+created with the new changes. If there are _no changes_ to the workflows, then
+the process will silently exit and you will not be notified.
+
+### Via GitHub
+
+To update your workflows in GitHub, go to
+`https://github.com/(ORGANISATION)/(REPOSITORY)/actions/workflows/update-workflows.yaml`
+
+Once there, you will see a button that says "Run Workflow" in a blue field to
+the right of your screen. Click on that Button and it will give you two options:
+
+1. "Who this build (enter github username to tag yourself)?
+2. "Workflow files/file extensions to clean (no wildcards, enter "" for none)
+
+You can leave these as-is or replace them with your own values. You can now hit
+the green "Run Workflow" button at the bottom.
+
+![](fig/update-workflow-manual.png){alt='Screen shot of GitHub interface zoomed into a button that says "Run workflow" with two options to specify your name (@zkamvar) and files to clean (.yaml). A green Run Workflow button is at the bottom of the dialogue.'}
+
+After ~10 seconds, your workflow will run and a pull request will be created
+from a GitHub bot (at the moment, this is @znk-machine) if your workflows are
+in need of updating.
+
+Check the changes and merge if they look okay to you. If they do not, contact
+@tobyhodges.
+
+
+### Via R
+
+If you want to update your workflows via R, you can use the
+`update_github_workflows()` function, which will report which files were updated.
+
+```r
+sandpaper::update_github_workflows()
+```
+
+```{.output}
+βΉ Workflows/files updated:
+- .github/workflows/pr-comment.yaml (modified)
+- .github/workflows/pr-post-remove-branch.yaml (modified)
+- .github/workflows/README.md (modified)
+- .github/workflows/sandpaper-version.txt (modified)
+- .github/workflows/update-workflows.yaml (new)
+```
+
+After that, you can add and commit your changes and then push them to GitHub.
+
+:::::: callout
+
+#### Do not combine workflow changes with other changes
+
+If you bundle a workflow changes in a pull request, you will not get the benefit
+of being able to inspect the output of the generated markdown files. Moreover,
+while we try to make these workflow files as simple as possible, they are still
+complex and would distract from any content that would be proposed for the
+lesson.
+
+:::::::::::::::
+
+
+::::::::::::::::::::::::::::::::::::: keypoints
+
+- Lesson structure, validation, and styling components are all updated
+ automatically on GitHub.
+- Lesson structure, validation, and styling components all live in your local
+ R library.
+- Locally, R packages can be updated with `install.packages()`
+- Package styling can be updated any time with `sandpaper::update_varnish()`
+- GitHub workflows live inside the lesson under `.github/workflows/`
+- GitHub workflows can be updated with `sandpaper::update_github_workflows()`
+
+::::::::::::::::::::::::::::::::::::::::::::::::
+