Skip to main content
We use md-babel-py to execute code blocks in markdown and insert results.

Golden Rule

All code blocks must be executable. Never write illustrative/pseudo code blocks. If you’re showing an API usage pattern, create a minimal working example that actually runs. This ensures documentation stays correct as the codebase evolves.

Running

skip
md-babel-py run document.md          # edit in-place
md-babel-py run document.md --stdout # preview to stdout
md-babel-py run document.md --dry-run # show what would run

Supported Languages

Python, Shell (sh), Node.js, plus visualization: Matplotlib, Graphviz, Pikchr, Asymptote, OpenSCAD, Diagon.

Code Block Flags

Add flags after the language identifier:
FlagEffect
session=NAMEShare state between blocks with same session name
output=path.pngWrite output to file instead of inline
no-resultExecute but don’t insert result
skipDon’t execute this block
expected-errorBlock is expected to fail
Use skip when a block would pull in CUDA / GPU-only stacks (for example perception models, VoxelGridMapper defaults, or imports that load torch with GPU expectations), or when it is flaky in CI (multi-module coordinators, timing-sensitive workers, pytest-style snippets that are not meant to run as a single script). Prefer expected-error only when the block is supposed to fail and you want to assert that failure.

Examples

md-babel-py

Execute code blocks in markdown files and insert the results. Demo Use cases:
  • Keep documentation examples up-to-date automatically
  • Validate code snippets in docs actually work
  • Generate diagrams and charts from code in markdown
  • Literate programming with executable documentation

Languages

Shell

echo "cwd: $(pwd)"
cwd: /home/lesh/coding/dimos

Python

session=example
a = "hello world"
print(a)
hello world
Sessions preserve state between code blocks:
session=example
print(a, "again")
hello world again

Node.js

console.log("Hello from Node.js");
console.log(`Node version: ${process.version}`);
Hello from Node.js
Node version: v24.11.1

Matplotlib

output=assets/matplotlib-demo.svg
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('dark_background')
x = np.linspace(0, 4 * np.pi, 200)
plt.figure(figsize=(8, 4))
plt.plot(x, np.sin(x), label='sin(x)', linewidth=2)
plt.plot(x, np.cos(x), label='cos(x)', linewidth=2)
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(alpha=0.3)
plt.savefig('{output}', transparent=True)
output

Pikchr

SQLite’s diagram language: output

Asymptote

Vector graphics:
output=assets/histogram.svg
import graph;
import stats;

size(400,200,IgnoreAspect);
defaultpen(white);

int n=10000;
real[] a=new real[n];
for(int i=0; i < n; ++i) a[i]=Gaussrand();

draw(graph(Gaussian,min(a),max(a)),orange);

int N=bins(a);

histogram(a,min(a),max(a),N,normalize=true,low=0,rgb(0.4,0.6,0.8),rgb(0.2,0.4,0.6),bars=true);

xaxis("$x$",BottomTop,LeftTicks,p=white);
yaxis("$dP/dx$",LeftRight,RightTicks(trailingzero),p=white);
output

Graphviz

output=assets/graph.svg
A -> B -> C
A -> C
output

Diagon

ASCII art diagrams:
mode=Math
1 + 1/2 + sum(i,0,10)
        10
        ___
    1   ╲
1 + ─ + ╱   i
    2   ‾‾‾
         0
mode=GraphDAG
A -> B -> C
A -> C
┌───┐
│A  │
└┬─┬┘
 │┌▽┐
 ││B│
 │└┬┘
┌▽─▽┐
│C  │
└───┘

Install

skip
# Run directly from GitHub
nix run github:leshy/md-babel-py -- run README.md --stdout

# Or clone and run locally
nix run . -- run README.md --stdout

Docker

skip
# Pull from Docker Hub
docker run -v $(pwd):/work lesh/md-babel-py:main run /work/README.md --stdout

# Or build locally via Nix
nix build .#docker     # builds tarball to ./result
docker load < result   # loads image from tarball
docker run -v $(pwd):/work md-babel-py:latest run /work/file.md --stdout

pipx

skip
pipx install md-babel-py
# or: uv pip install md-babel-py
md-babel-py run README.md --stdout
If not using nix or docker, evaluators require system dependencies:
LanguageSystem packages
pythonpython3
nodenodejs
dotgraphviz
asymptoteasymptote, texlive, dvisvgm
pikchrpikchr
openscadopenscad, xvfb, imagemagick
diagondiagon
skip
# Arch Linux
sudo pacman -S python nodejs graphviz asymptote texlive-basic openscad xorg-server-xvfb imagemagick

# Debian/Ubuntu
sudo apt-get install python3 nodejs graphviz asymptote texlive xvfb imagemagick openscad
Note: pikchr and diagon may need to be built from source. Use Docker or Nix for full evaluator support.

Usage

skip
# Edit file in-place
md-babel-py run document.md

# Output to separate file
md-babel-py run document.md --output result.md

# Print to stdout
md-babel-py run document.md --stdout

# Only run specific languages
md-babel-py run document.md --lang python,sh

# Dry run - show what would execute
md-babel-py run document.md --dry-run

# Longer subprocess limit (default 60s); see upstream README for MD_BABEL_EXECUTION_TIMEOUT
md-babel-py run document.md --execution-timeout 120