07. Examples and execution
Every piece of code on the site is executed by the build, or is marked with the reason why it is not. This is the main difference between this site and the reference sites that disclaim correctness (Rosetta Code shows output pasted by hand; Programming-Idioms says it gives no guarantee, 01.3). This document defines the example markup, the runner, the images, the version matrix, the output rules, and the reader's playground.
7.1 Decisions
| Decision | Choice | Why |
|---|---|---|
| One harness or each language's doctest? | One harness (prog run) for all languages |
25 doctest dialects (rustdoc, Python doctest, Go Example, ExUnit doctest, sol/doctest, mdx, ...) have 25 sets of rules; one harness gives one set of attributes, one output normalizer and one cache |
| Where do examples live? | In Markdown, in fenced blocks with attributes, parsed with a CommonMark AST (goldmark, as in the markup package) |
the page source is the test source; no copy to drift |
| Where do they run in CI? | In OCI images pinned by digest, one per language version, under gVisor (runsc) with no network and a read-only root |
the algorithm sandbox, extended to many versions |
| Is output typed by hand? | Never. prog run -update writes the output blocks, as dune promote and prysk -i do |
output typed by hand drifts |
| Can readers run code? | Yes, in the browser, where a WebAssembly runtime exists (7.10). No server execution for readers in v1 (Default; 22, Q-07) | static site, no cost per reader, no abuse surface |
| Pinning | image digests plus mise or uv inside the image; Nix optional |
Nix flakes are still experimental in upstream Nix in Oct 2026 (01.4) |
7.2 Block attributes
A fenced code block's info string is the language name and then attributes. The language name is the id of registers/languages.yaml (python, rust, cpp, sql, bash, ...) or an alias of it.
| Attribute | Meaning | Default |
|---|---|---|
run |
run the block; it must exit 0 and its output must match the next output block |
none |
fails |
run the block; it must fail as declared by expect= |
none |
expect=<sig> |
the failure signature: compile, runtime, exit:<n>, exception:<Type>, error:<code> (a diagnostic code such as E0382 or TS2339), panic, timeout, sanitizer:<kind> |
none |
wrong |
run the block; it exits 0, but the output is the wrong answer that the page explains | none |
norun reason="..." |
do not run; the reason is required and must be one of the codes of 7.8 | none |
id=<name> |
a stable id, unique on the page; it is the anchor and the key of the recorded output | the build assigns ex1, ex2, ... and the linter asks for an id at W3 |
since=<v> |
the example needs version v or later; the K check (09.4) runs it on the version before and expects failure | the language's support window floor |
until=<v> |
the example works up to version v; it fails after (for removed features) | none |
version=<v> |
run only on version v (for side-by-side behaviour changes) | none |
version=matrix |
run on every version of the support window (the X3 check) | X3 runs the matrix for every run block anyway; this attribute marks a block that is about the matrix |
impl=<id> |
run on this implementation only (pypy, graalpy, clang, msvc, bun, ...) |
the language's default implementation |
std=<x> |
the language standard flag (c17, c23, c++20, c++23, es2026) |
the newest standard in the image |
flags="..." |
extra compiler or interpreter flags from the allow list of the language | none |
file=<name> |
the block is a file of a multi-file example, with its path | main.<ext> |
group=<name> |
the blocks with the same group are one program (multi-file, or a program shown in parts) | none |
prelude=<id> |
prepend a hidden block (shown in a <details>) |
none |
stdin=<id> |
feed the named input block to stdin |
empty |
args="..." |
command-line arguments | none |
deps=<lock> |
the example uses packages pinned in a lock file of the node (7.7) | none |
timeout=<s> |
wall-time limit in seconds, up to 30 | 10 |
browser |
the reader may run it in the playground (7.10); the build checks that the browser runtime gives the same output | on when the language has a browser runtime and the block has no deps, file or OS use |
lint="rule,rule" |
lint rules turned off for this block, each with a reason in the node's notes | none |
platform=<os> |
linux (default), windows, macos; non-Linux blocks run in the scheduled jobs of 7.5 |
linux |
Output blocks:
```python run id=split-basic
print("a,b,,c".split(","))
```
```output for=split-basic
['a', 'b', '', 'c']
```
| Output attribute | Meaning |
|---|---|
for=<id> |
the block whose output this is; required |
stream=stdout|stderr|both |
which stream; both interleaves as the terminal showed it |
match=exact|regex|unordered|any |
exact after normalization (7.6); each line a regex; the same lines in any order (sets, maps, threads); any output (only the exit status counts) |
normalize="addr,time,tmp,hash,float:6" |
extra normalizers: memory addresses, timestamps, temp paths, hash ids, float precision |
version=<v> |
the output on version v, when it differs between versions |
Rules:
- X01: every fenced code block has a language and exactly one of
run,fails,wrong,norun. A block of a language that is not in the register (for example a pseudo-language or a grammar) must betext,ebnf,abnf,pegor another notation id ofregisters/notations.yaml. - X02: every
runandwrongblock has anoutputblock, unlessmatch=any. - X03: every
outputblock was written byprog run -update. The build stores the hash of each recorded output inbuild/runs/and fails if the text in the page differs from the last recorded run. - X04: a
failsblock fails with exactly the declared signature. A compile error with another code, or a runtime error of another type, fails the check. - X05: an
expect=error:<code>points to a diagnostic card that exists (04.2), so that every diagnostic shown on the site links to its card.
7.3 Programs, fragments and preludes
Most examples are complete programs. Some languages need a lot of ceremony for a complete program (Java's class and main, C's includes). The harness supports wrappers so the page can show the important lines only:
- Each language has wrappers in
languages/<lang>/wrappers/:program(none),main(put the block insidemain),expr(print the value of the expression, as a REPL would),repl(run as a REPL session: lines that start with the language's prompt,>>>,>,iex>,ghci>,scala>,jshell>, are input and the rest is output). A block selects a wrapper withwrap=<name>. wrap=replblocks have their output inside the block, as a REPL session shows it. The harness checks the output lines against the run. This is the doctest model, made language-neutral.- A hidden prelude (
prelude=<id>) is shown under a<details>element named "Setup code". The copy button copies the prelude and the block together, so that the reader always gets a complete program. - X06: the copied text of every block (prelude, wrapper, block) is a program that runs. The build tests it in this form.
7.4 The runner and the images
prog run extracts the blocks with the CommonMark AST, groups them, wraps them, and runs each one in its image.
Images. One OCI image per language version (and per implementation where the page uses it), named ghcr.io/tamnd/prog-runner/<lang>:<version>, used only by digest. registers/images.yaml lists the digests. The image contains the toolchain, the language's formatter and linter at pinned versions, the test framework of 10.3, and nothing else.
| Source of the base | When |
|---|---|
| the Docker official image (python, pypy, golang, rust, node, ruby, php, gcc, haskell, elixir, erlang, swift, julia, perl, r-base, dart, clojure, groovy, nim, eclipse-temurin, ...) pinned by digest | when one exists; 141 official images in Nov 2026 |
the vendor's image (mcr.microsoft.com/dotnet/sdk, ocaml/opam) |
when the vendor publishes one |
our own Dockerfile with mise (Zig, Kotlin, Scala, Lua, Deno, Bun, ...) or uv python install |
otherwise |
The version matrix of tier 1 at M0 (Draft; 09.3 sets the support window rule):
| Language | Versions in the matrix | Implementations |
|---|---|---|
| Python | 3.9 (for the since checks of 3.10 features) to 3.15, and 3.16 alphas in a scheduled job |
CPython; PyPy 3.11 for the pages that name it |
| JavaScript | Node.js 18 to 26; the ECMAScript edition gates use Node's --harmony flags only when the page says so |
V8 (Node), Bun, Deno for pages that name them; browsers are covered by BCD data, not by our runs (09.6) |
| TypeScript | 4.9, each minor of 5.x, 6.0 (the last compiler written in TypeScript), 7.0 and later (the native Go port, GA 2026-07-08), on the newest Node | tsc (both lines); the type checking result is the output of fails expect=error:TS<n> blocks |
| Java | 8, 11, 17, 21, 25 (LTS) and the newest feature release (JDK 27 in Nov 2026) | Temurin |
| C | GCC 9 to 15 and Clang 12 to 21, each with every -std it supports |
GCC, Clang; MSVC in the scheduled Windows job |
| C++ | as C, with -std=c++11 to c++23, and c++26 (c++2c) as a draft standard: WG21 finished the text in March 2026, but the ISO DIS ballot failed in Oct 2026 (01.4) |
GCC, Clang, MSVC (scheduled) |
| C# | .NET 6, 8, 10 (LTS) and the newest STS (.NET 11, GA planned 2026-11-10) | .NET SDK |
| Go | the newest 8 minor versions (1.20 to 1.27) | gc; TinyGo for pages that name it |
| Rust | 1.56 (edition 2021), each sixth stable release after it, and the newest stable (1.99 in Nov 2026); editions 2015, 2018, 2021, 2024 | rustc |
| Kotlin | 1.9, 2.0 to the newest, on the JVM | kotlinc |
| SQL | SQLite 3.x newest, PostgreSQL 13 to 18, MySQL 8.0, 8.4 and 9.x, MariaDB LTS, DuckDB newest | each dialect is an implementation column of the SQL compat (09.2) |
| Bash | 3.2 (the macOS system bash), 4.4, 5.0 to 5.3; dash and zsh for the portability pages; BusyBox ash | none |
| Regex | engines as implementations: PCRE2, Python re, JS (V8), Java, .NET, Go RE2, Rust regex, POSIX ERE (GNU grep) |
none |
| HTML/CSS | rendered in headless Chromium and Firefox for pages that show rendering; the compat facts come from BCD | none |
| PowerShell | 5.1 (scheduled Windows job), 7.4 LTS and newest | none |
Tier 2 has the newest version and the oldest supported one at M3, and the full matrix at M4.
Sandbox. As in algorithm (algo test): no network, a read-only root with a tmpfs work directory, a user with no privileges, cgroup limits (CPU 1 core, memory 512 MiB by default, PIDs 64), and the wall timeout. CI runs the images under gVisor (runsc). Local runs use Podman rootless or Docker, and -unsafe-local runs on the host for development only, as in algorithm.
Cache. A result is keyed by BLAKE3(image digest, wrapper, flags, stdin, the block group's text). A run whose key is in the cache is skipped. A change of an image digest re-runs every block that uses it, which is how a new compiler release finds regressions in our pages.
Sharding. CI shards by image across the free ubuntu-24.04 and ubuntu-24.04-arm runners, as algorithm does by language. Examples with platform=windows or platform=macos run in a scheduled weekly job on windows-latest (Server 2025) and macos-latest (macOS 26 arm64), not on each PR (Default).
7.5 What examples may not do
- No network. An example that shows an HTTP client runs against a local server that the harness starts in the same sandbox (
fixture=http:<name>, fromfixtures/http/), or it isnorun reason=networkwith recorded output from a scheduled job. - No clock or random dependence in exact output. Use a fixed seed, or
match=regex, or thetimenormalizer. Concurrency examples whose order varies usematch=unordered. - No files outside the work directory. Fixtures are copied into it.
- No GUI. GUI examples are
norun reason=guiwith a screenshot taken in a scheduled job with a virtual display (12.7). - No undefined behaviour shown as a working program. A C or C++ example that has UB is
fails expect=sanitizer:<kind>under UBSan or ASan, ornorun reason=ubwith the explanation. A page never shows "the output" of a UB program as if it were defined.
7.6 Output normalization and the X ladder
Default normalizers, applied to both the recorded and the actual output before the compare: CRLF to LF, trailing whitespace on each line removed, a final newline added, ANSI colour codes removed, the work-directory path replaced by $WORK, the image's home directory by $HOME. Per-language normalizers in languages/<lang>/normalize.yaml, for example Python's <object at 0x...> addresses, Java's @1b6d3586 identity hashes, Go's goroutine ids in panics, Rust's thread 'main' panicked at src/main.rs:LL:CC.
X3 needs each run block to pass on every version of the language's support window (09.3) that is not before its since or after its until. When the output differs between versions, the page must show both outputs with version= (6.7). A difference that the page does not show fails X3: this is how the build finds behaviour changes that a page did not mention (for example dict ordering, integer division, a changed error message).
Error messages change between versions. A fails block checks the signature (the code or the exception type), not the message text. The output block of a fails block shows the message of the newest version, with match=regex on the stable part.
7.7 Third-party packages
- An example on a page that is not about a library uses the standard library only (X07).
- A page about a library (a
librarynode, or a task that names a library as the idiomatic way) may use it withdeps=<lock>. The node holds the lock file (requirements.lock,Cargo.lock,package-lock.json,go.sum,pom.xmlwith versions, ...). The image fetches packages once at build time from a mirror into a cache layer; the run itself still has no network. - The library's version is part of the example's facts and shows on the page.
7.8 Reasons for norun
| Code | Meaning | What the build does instead |
|---|---|---|
network |
needs a real network | scheduled job with network, recorded output, marked "recorded on " |
gui |
needs a display | scheduled job with Xvfb, screenshot |
platform |
needs Windows or macOS | scheduled job on that runner |
hardware |
needs a GPU, a microcontroller, special hardware | none; the page says so; the example must still compile (compile-only) where a toolchain exists |
ub |
undefined behaviour shown on purpose | compile only, with the sanitizer check where possible |
vulnerable |
a weakness example (06.3, weakness) | runs only inside the security harness with the exploit input (10.8) |
fragment |
a part of a larger program, for reading only | the group that holds the full program must run |
pseudo |
not code of a real language (should be rare) | none; the linter asks to change it to text |
long |
needs more than 30 seconds | scheduled job |
interactive |
needs a person at a terminal | a scripted session with expect, when possible |
compile-only is a mode of its own: the block is compiled (or type-checked, or parsed) but not run. It is the default for norun with hardware, ub, fragment when the language has a compiler.
Rule X08: norun blocks are at most 10% of the blocks of a node, except for nodes in embedded-and-hardware, graphics-and-games-programming, mobile-and-desktop and distributed-and-cloud, where the limit is 40%.
7.9 Benchmarks
A benchmark claim on a page ("X is about 3 times faster than Y for this input") needs a benchmark block: bench with the harness of the language (pytest-benchmark, criterion, JMH, Go testing.B, BenchmarkDotNet, google-benchmark), run in a scheduled job on a fixed runner class, with the result recorded with the hardware, the versions and the date. The page shows the result as a range, with "recorded on", and never as a fact about the languages in general. Rule X10.
7.10 The reader's playground
The reader can edit and run an example in the browser where a WebAssembly runtime runs it. The runtime loads in a Web Worker on the first click of "Run", never on page load. The site serves the runtimes itself, from R2, under cross-origin isolation headers (COOP and COEP) on the playground routes only (16.8).
| Language | Browser runtime (Nov 2026) | Size, gzip (measured, 01.4) | Default |
|---|---|---|---|
| Python | Pyodide 314.0.x (CPython 3.14) | about 6 MB with the stdlib zip | on |
| Python (quick) | MicroPython 1.29 | about 200 KB | on for intro pages, with a "full Python" switch |
| JavaScript | the browser itself, in a sandboxed iframe or a Worker; QuickJS-wasm for isolation | none | on |
| TypeScript | the typescript compiler in a Worker, then JS |
about 3 MB | on |
| SQL | sqlite-wasm 3.54 (about 400 KB); PGlite 0.5 for PostgreSQL pages (about 5 MB) | on | |
| Lua | wasmoon (Lua 5.4) | about 110 KB | on |
| Ruby | ruby.wasm, minimal build | about 5 MB | on |
| PHP | php-wasm | not measured | on |
| OCaml | wasm_of_ocaml toplevel 6.5 | about 9 MB | on |
| Regex | each engine as wasm or JS: PCRE2 wasm, the JS engine, RE2 wasm, Rust regex wasm |
small | on |
| Bash | a POSIX shell in wasm with BusyBox (Default: off until tested) | off | |
| C, C++ | Clang in wasm (Runno, xeus-cpp) | large | off (experimental flag) |
| Java | TeaVM with javac in the browser (subset of the JDK) | not measured | off (experimental flag) |
| Go, Rust, Kotlin, Swift, C#, Haskell, Elixir, Zig, others | no maintained in-browser compiler in Nov 2026 | none | "Open in the official playground" with the code passed in the URL where the playground supports it (go.dev/play, play.rust-lang.org, play.kotlinlang.org, Compiler Explorer, SwiftFiddle) |
Rules:
- X11: a block marked
browsergives the same normalized output in its browser runtime as in CI. The build runs the browser runtimes headless (Node or Chromium) on every block markedbrowser. A mismatch removes thebrowsermark and opens a gap item. - The playground shows the recorded CI output next to the reader's output. When the reader has not changed the code and the outputs differ, it shows a notice ("this runtime differs from the CI run") with the version of each.
- The playground never sends code to our servers. "Open in" links send code to the third party only when the reader clicks, with a notice.
- A server-side "Run" for compiled languages (Judge0 CE or Piston self-hosted, or Cloudflare Sandbox SDK with our images) is not in v1. 22, Q-07 holds the question. Piston's public API closed in Feb 2026 and TIO is dormant, so no public free service is assumed.
7.11 The examples dataset
The build emits build/data/examples.jsonl: one row per block with the page, the id, the language, the version range, the implementation, the code (as the reader copies it), the recorded output, the run status per version, and the hashes. It is published under MIT (the code) and CC0 (the metadata) on the site and on Hugging Face (16.10). It is the "language × feature × version" dataset that no one publishes today (01.3).