Write a lab
A lab is one Markdown file in its own folder, with its screenshots beside it. You don't need to touch the site's code. Copy the template, write the steps, and preview it locally.
Preview on your machine
You need Node.js 22.12 or newer.
git clone https://github.com/BESSER-PEARL/BESSER-education
cd BESSER-education
npm install
npm run devOpen the address it prints. Copy src/content/labs/_template/ to a new folder, for examplesrc/content/labs/state-machines/, and the lab appears at /labs/state-machines/while you edit.
Building blocks
| Write | To get |
|---|---|
## Heading | A numbered step in the progress rail |
:::checkpoint | What the learner should see before moving on |
:::exercise[Name] | An open task at the end of the lab |
:::solution | A collapsed hint or partial solution |
:::note, :::tip | Side information, styled as a UML note |
:::caution | Costs, accounts and things that can't be undone |
:::troubleshoot | The most likely failure and its fix |
:ui[File > Export] | An interface label, exactly as shown on screen |
:kbd[Ctrl+S] | A keyboard key |
 | A figure with a caption |
What makes a good lab
- It ends with something running that the learner can show someone.
- Every step ends in a checkpoint the learner can verify on their own screen.
- Screenshots come from the real editor at the release named in
version, never mock-ups. - Interface labels match the editor exactly, including capitalisation.
- The duration is measured on someone doing it for the first time.
- Anything that costs money or needs an account is called out before the step that needs it.
Publishing
Set draft: false, run npm run build to catch errors, and open a pull request. The site rebuilds and publishes when the pull request is merged into main.
The template
Also in the repository at src/content/labs/_template/index.md.
---
# Copy this folder to src/content/labs/<your-lab-id>/ and edit. The folder name becomes the URL.
title: Short task-shaped title
number: 99 # position in the curriculum; renumber freely
track: foundations # foundations | ai | data | apps | agents | extend
summary: One sentence saying what the learner has at the end.
duration: 45 # minutes for a first-timer, honestly measured
level: Beginner # Beginner | Intermediate | Advanced
setup: [Browser] # any of: Browser, Python, Docker, GitHub, API key
needs:
- A modern browser
outcomes:
- Something the learner can do afterwards, starting with a verb
before: [] # lab ids to do first, e.g. [first-model]
files: [] # downloads in /public, e.g. [{ label: "Starter model (JSON)", href: "/files/my-lab/model.json" }]
updated: 2026-10-02
version: "8.0.1" # BESSER release you checked the steps against
draft: true # drafts only show in `npm run dev`
---
One or two paragraphs of context: the scenario and why it matters. No heading here.
## First task, named as an action
Every `##` heading is a numbered step and appears in the progress rail. Keep steps to
things a learner can finish and check in five to ten minutes.
1. Use the exact labels from the interface: open :ui[File > New Project].
2. Keyboard keys look like :kbd[Ctrl+S].

:::checkpoint
What the learner should see now. Be concrete: "The class has three attributes and Quality
Check reports no errors."
:::
## Second task
:::note
A UML-style note for context that is useful but not required.
:::
:::caution
Anything that costs money, needs an account, or can't be undone.
:::
:::troubleshoot
The most common way this step fails, and what to do about it.
:::
## Exercise
:::exercise[Short name of the exercise]
An open task that applies what the lab taught, without step-by-step instructions.
:::
:::solution
A short hint or a partial solution. Full solutions live in the private educators repository.
:::