Everything below exists in the repository today, and everything that grades you runs against a real machine. Where something is planned rather than built, it says so.
A lab is a directory of faults, checks, hints and a reference solution. The grading is the product.
Pinned, reproducible, and built so that a broken guest cannot break grading.
norboten opens one full-screen interface. Everything a learner does is a key in it, and doctor has already checked the machine by the time the first screen draws.
Ctrl+P lists what the app can do.A wrong question teaches a wrong thing, so the pipeline is stricter than the writing.
A journal is what a good colleague would explain after the lab: how the thing works, and how it goes wrong.
A recording of someone fixing a machine says more than any feature list. So the terminal is recordable, and the recording is honest.
Optional, and off the critical path: everything works signed out. What an account adds is a measurement you can argue with.
The format is small enough to hold in your head, and the gate tells you the truth before a reviewer has to.
A manifest, a briefing that states symptoms only, break scripts, check scripts, a hint ladder and a reference solution.
norboten dev lint checks the manifest, the hint ladder, the objective mapping and that guest scripts import nothing but the standard library.
norboten dev validate runs the whole gate locally, on each base image the lab claims to support.
Labs are built from images/Dockerfile.lab, pushed to GHCR and signed with cosign; u in the Labs section pulls and verifies one.
The server side is one machine and one Docker Compose project, described in code and rehearsed on a laptop before it touches a server.
One netcup VPS, ordered by hand and bootstrapped by Ansible. No managed services, no Kubernetes: learners' VMs run on learners' machines, so the server carries accounts, text and a small model.
ansible/playbooks/bootstrap.yml · 2 vCPU, 4 GB
Firewall, unattended upgrades, keys-only SSH, Docker; then Caddy, the API, PostgreSQL, Redis, Ollama, Prometheus and Grafana as one compose project.
A push to main tests against real PostgreSQL and Redis, builds the image and the site, and runs deploy.sh — which goes back to the previous tag if the new one does not report ready.
The nightly job restores the dump it just took into a scratch database and counts rows before it keeps it, then copies it off the box with restic.
make stack-up runs the production compose project locally with sample data; make server-rehearsal runs the production playbook against an Ubuntu VM.
Public, offline, complete. The faults, the checks and the reference solution are in the repository; reading them is allowed and often the point. No account, no server, no clock unless you ask for one. This is the larger half, and it is what the catalogue on this site lists today.
Graded by the server against your account, and the only work that moves a rating. Their answers are not published: the material lives in a private repository attached here as the rated/ submodule, the verdict is computed away from your machine, and what reaches the guest never lands in ~/.norboten.
Why it is split that way, how a rated attempt is graded from signed machine state, and the honest limit of doing it at all: Rated and unrated labs.
Not mock-ups: Textual renders the running app to SVG, so these are the real widget tree at the real size. Ratings and profiles show generated sample accounts. make captures regenerates them.