Multi-book Quarto monorepo. Each book under books/ builds to HTML, PDF, and EPUB; a library portal is assembled under books/published_books/ and deployed to GitHub Pages.
Agent / maintainer notes: root AGENTS.md (pipeline, naming). Illustrated SVG style: includes/diagrams/STANDARD.md.
| Book | Path | Focus |
|---|---|---|
| C | books/C/ |
C17 modular library + workbook |
| Go | books/Go/ |
Deep Go library (paths A–G, projects) |
| Linux | books/Linux/ |
Commands + Editors + Bash |
| Maths | books/Maths/ |
CS / ML mathematics library |
| Networking | books/Networking/ |
First principles → NetOps + Containerlab |
| NixOS | books/NixOS/ |
Nix & NixOS (Fedora bridge → fleet) |
| VCS | books/VCS/ |
Version control; Git under content/01-git/ |
Single-book build from books/: ./indipub.sh <Name> (e.g. ./indipub.sh VCS).
Install these before rendering or previewing locally. CI installs its own toolchain on Ubuntu (see .github/workflows/incremental.yml).
Primary authoring platforms: macOS and Linux (bash scripts). Windows: use WSL2 (Ubuntu) for full parity, or Git Bash with limitations (below).
| Tool | Why |
|---|---|
| Quarto | Renders HTML / PDF / EPUB. CI pins 1.3.450; local 1.4+ / 1.10.x usually fine. |
| Bash | books/indipub.sh, indiprev.sh, renderpub.sh, each book’s scripts/update-index.sh. |
| Python 3 | Preview server (indiprev.sh) and helpers (python3 on PATH). |
| Git | Clone and CI change detection. |
| TeX (TinyTeX or TeX Live) | PDF via LuaLaTeX / related engines. Put lualatex + tlmgr on PATH. |
rsvg-convert (librsvg) |
Quarto converts SVG figures → PDF. Without it, topology diagrams fail or look wrong in PDF. |
HTML-only can skip TeX:
cd books/<BookName>
quarto render --to htmlPandoc is bundled with Quarto — no separate install. Node/Deno are managed by Quarto.
TeX packages: first PDF render may pull packages via tlmgr (network). Match tlmgr’s repository to your TeX Live year (frozen historic mirror if needed). CI package list: ci/tinytex-packages.txt; setup: books/scripts/setup-ci-tinytex.sh.
Recommended: Homebrew + TinyTeX (or MacTeX if you already use it).
# Package manager
# https://brew.sh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Quarto
brew install --cask quarto
# SVG → PDF (rsvg-convert)
brew install librsvg
# Python 3 (if missing)
brew install python
# Git (if missing)
brew install git
# TinyTeX — minimal TeX for PDF (pick one approach)
# A) Official TinyTeX: https://yihui.org/tinytex/
# B) Or full MacTeX: https://www.tug.org/mactex/ (large download)After TinyTeX install, engines are often not on the default PATH:
# Apple Silicon / universal TinyTeX (common layout)
export PATH="$HOME/Library/TinyTeX/bin/universal-darwin:$PATH"
# Persist (zsh):
echo 'export PATH="$HOME/Library/TinyTeX/bin/universal-darwin:$PATH"' >> ~/.zshrc
# Also ensure Homebrew is on PATH (Apple Silicon):
# echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zshrcRepo scripts prepend /opt/homebrew/bin automatically when present.
quarto --version
python3 --version
which rsvg-convert lualatex tlmgr
quarto check
cd books
./indipub.sh Networking # HTML + PDF + EPUB
./indiprev.sh Networking # HTTPS preview (Safari default)
./indiprev.sh Networking --browser "Google Chrome"indiprev.shdefaults to HTTPS on localhost (Safari-friendly) and Safari.- First visit may need to trust the local self-signed cert under
books/.preview-certs/. - OpenSSL/LibreSSL is usually already available.
CI runs on Ubuntu. Local authoring is fully supported on Fedora and other distros with the packages below. The critical PDF dependency that differs by distro name is rsvg-convert.
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
curl ca-certificates git python3 \
librsvg2-bin unzip xz-utils openssl
# Quarto: install the .deb from https://quarto.org/docs/get-started/
# Example (check site for current version/arch; CI pins 1.3.450):
# curl -LO https://github.com/quarto-dev/quarto-cli/releases/download/v1.3.450/quarto-1.3.450-linux-amd64.deb
# sudo dpkg -i quarto-1.3.450-linux-amd64.deb
# TinyTeX (user-local; matches CI) — https://yihui.org/tinytex/
# or system TeX Live:
# sudo apt-get install -y texlive-xetex texlive-luatex texlive-latex-recommended texlive-fonts-recommendedrsvg-convert package name on Debian/Ubuntu: librsvg2-bin.
Tested shape: Fedora 40+ (including Fedora 44) with user-local Quarto + TinyTeX. Same commands work on RHEL-family clones via dnf / yum.
sudo dnf install -y \
git curl ca-certificates python3 \
unzip xz openssl \
librsvg2-tools| Package | Provides | Notes |
|---|---|---|
librsvg2-tools |
/usr/bin/rsvg-convert |
Required for PDF. Name is not librsvg2 alone — the tools subpackage ships the CLI. |
git, python3, curl, openssl |
clone, indiprev.sh, HTTPS |
Usually already present on desktop Fedora. |
Without rsvg-convert, Quarto aborts PDF when a book embeds SVG (e.g. Networking topology diagrams):
ERROR: Failed when attempting to convert a SVG to a PDF for output.
Please ensure that rsvg-convert is available on the path.
indipub.sh uses set -e, so a PDF failure stops that book’s EPUB/HTML passes too. Fix PATH / install librsvg2-tools, then re-run.
Official releases: https://quarto.org/docs/get-started/ and https://github.com/quarto-dev/quarto-cli/releases.
# Example for amd64; bump version as needed (CI pins 1.3.450)
VER=1.3.450
mkdir -p "$HOME/.local/opt" "$HOME/.local/bin"
cd /tmp
curl -fL -o "quarto-${VER}-linux-amd64.tar.gz" \
"https://github.com/quarto-dev/quarto-cli/releases/download/v${VER}/quarto-${VER}-linux-amd64.tar.gz"
tar -xzf "quarto-${VER}-linux-amd64.tar.gz" -C "$HOME/.local/opt"
# tarball expands to a versioned directory; symlink a stable name:
ln -sfn "$HOME/.local/opt/quarto-${VER}" "$HOME/.local/opt/quarto"
ln -sfn "$HOME/.local/opt/quarto/bin/quarto" "$HOME/.local/bin/quarto"
# Ensure ~/.local/bin is on PATH (bash):
grep -q '.local/bin' ~/.bashrc || \
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
# fish:
# fish_add_path $HOME/.local/binMatches CI idea (user-local engines + tlmgr):
# https://yihui.org/tinytex/
curl -sL "https://yihui.org/tinytex/install-bin-unix.sh" | sh
# PATH — engines live under ~/.TinyTeX (not system texlive)
export PATH="$HOME/.TinyTeX/bin/x86_64-linux:$PATH"
# aarch64:
# export PATH="$HOME/.TinyTeX/bin/aarch64-linux:$PATH"
# Persist (bash):
echo 'export PATH="$HOME/.TinyTeX/bin/x86_64-linux:$PATH"' >> ~/.bashrc
# fish:
# fish_add_path $HOME/.TinyTeX/bin/x86_64-linux
# Optional: install monorepo TeX extras the way CI does (from repo root):
# bash books/scripts/setup-ci-tinytex.sh # or follow ci/README.md + ci/tinytex-packages.txtBooks in this monorepo often use XeLaTeX (xelatex) as well as LuaLaTeX. After TinyTeX is on PATH:
which xelatex lualatex tlmgrIf you prefer distro packages instead of TinyTeX (larger download, different upgrade path):
sudo dnf install -y \
texlive-scheme-basic \
texlive-xetex \
texlive-luatex \
texlive-collection-latexrecommended \
texlive-collection-fontsrecommended
# Extra packages may still be needed for some books; tlmgr is TinyTeX-oriented.Prefer one TeX install on PATH to avoid mixed-year tlmgr confusion.
If you cannot sudo dnf install but can download packages:
mkdir -p /tmp/rsvg-extract "$HOME/.local/bin"
cd /tmp/rsvg-extract
dnf download librsvg2-tools
rpm2cpio librsvg2-tools-*.rpm | cpio -idmv
cp -a ./usr/bin/rsvg-convert "$HOME/.local/bin/"
export PATH="$HOME/.local/bin:$PATH"
rsvg-convert --version
# Shared libs usually already exist via other GUI packages; check:
# ldd "$HOME/.local/bin/rsvg-convert" | grep 'not found'export PATH="$HOME/.local/bin:$HOME/.TinyTeX/bin/x86_64-linux:$PATH"
quarto --version # expect 1.3.x or newer
python3 --version
which rsvg-convert xelatex lualatex tlmgr
rsvg-convert --version
quarto check
cd books
./indipub.sh Networking # single book: HTML + PDF + EPUB
./indipub.sh Linux # merged Commands / Editors / Bash book
./renderpub.sh # full library + published_books portal
./indiprev.sh Networking --browser "firefox"
# or:
./indiprev.sh Networking --http --browser "firefox"Portal output: books/published_books/index.html (gitignored; regenerate with bash scripts/gen-portal.sh after harvesting).
| Need | Fedora (dnf) |
Debian/Ubuntu (apt) |
|---|---|---|
| SVG → PDF CLI | librsvg2-tools |
librsvg2-bin |
| Python 3 | python3 |
python3 |
| Git / curl | git curl |
git curl |
| Quarto | tarball → ~/.local (or COPR if you prefer) |
.deb from releases |
| TeX | TinyTeX or texlive-xetex / schemes |
TinyTeX or texlive-* |
sudo pacman -S git python librsvg curl openssl unzip
# yay/paru or manual: quarto-bin; texlive-basic or TinyTeX
# rsvg-convert: package name is librsvg# After TinyTeX install, bin is typically:
export PATH="$HOME/.TinyTeX/bin/x86_64-linux:$PATH"
# arm64:
# export PATH="$HOME/.TinyTeX/bin/aarch64-linux:$PATH"
# Persist (bash):
echo 'export PATH="$HOME/.TinyTeX/bin/x86_64-linux:$PATH"' >> ~/.bashrc
# fish:
# fish_add_path $HOME/.TinyTeX/bin/x86_64-linuxAlso keep ~/.local/bin on PATH if Quarto or a user-local rsvg-convert lives there.
quarto --version
python3 --version
which rsvg-convert lualatex tlmgr
quarto check
cd books
./indipub.sh Networking
./indiprev.sh Networking --browser "firefox" # or chromium
# or plain HTTP if preferred:
./indiprev.sh Networking --http --browser "firefox"indiprev.shstill works; pass--browser(no Safari). Common:firefox,chromium-browser,google-chrome.- OpenSSL is usually present via the
opensslpackage if cert generation is needed. - On fish, export PATH with
fish_add_path(see Fedora section) rather thanexportin~/.bashrconly.
GitHub Actions (Ubuntu) roughly: Quarto 1.3.450, TinyTeX + ci/tinytex-packages.txt, librsvg2-bin.
Local Fedora with TinyTeX + librsvg2-tools + the same Quarto pin is a supported authoring setup; PDF/HTML/EPUB should match CI for content (engine package sets can still differ slightly from apt TeX).
Recommended path: WSL2 + Ubuntu. The monorepo’s build/preview scripts are bash. Native PowerShell is not a first-class path for indipub.sh / renderpub.sh.
- Install WSL2 and an Ubuntu distro (Microsoft Store or
wsl --install). - Open the Ubuntu shell and follow the Linux (Ubuntu / Debian) section above.
- Clone or open the repo inside the Linux filesystem (e.g.
~/src/books) for best I/O performance — avoid building only from/mnt/c/...if possible. - Run builds from the WSL shell:
cd /path/to/repo/books
./indipub.sh Networking
./indiprev.sh Networking --http --browser "" # open the printed URL from Windows browser if needed
# or: quarto preview books/NetworkingQuarto and TeX should be installed inside WSL, not only on Windows, so PATH is consistent.
| Piece | How |
|---|---|
| Git for Windows | Provides Git Bash so you can run ./indipub.sh / update-index.sh. |
| Quarto | Windows installer — ensure “Add to PATH”. |
| Python 3 | python.org or winget install Python.Python.3.12 — enable “Add to PATH”; use python / py if python3 is missing. |
| TinyTeX / TeX Live | TinyTeX or TeX Live for Windows. Add the TinyTeX bin/windows directory to the User PATH. |
| rsvg-convert | Easiest via MSYS2 (pacman -S mingw-w64-x86_64-librsvg) or a Scoop/Chocolatey package that ships rsvg-convert. Must be on PATH for PDF figures. |
Example Git Bash session:
# Git Bash
cd /c/Users/you/src/books/books
export PATH="/c/Program Files/Quarto/bin:$PATH"
# Add TinyTeX and rsvg bins as installed:
# export PATH="$HOME/AppData/Roaming/TinyTeX/bin/windows:$PATH"
quarto --version
./indipub.sh Networkingindiprev.shis oriented toward macOS Safari/HTTPS; on Windows prefer:quarto previewfrom the book directory, or- WSL +
--httpand open the URL in Edge/Chrome.
- Line endings: keep shell scripts as LF (
git config core.autocrlf inputrecommended for this repo).
- Running
indipub.shfrom cmd.exe / pure PowerShell without Bash. - Expecting CI’s exact Ubuntu TinyTeX layout under native Windows without adjusting PATH.
| Variable | Purpose |
|---|---|
PATH |
Must include Quarto, TeX (lualatex/tlmgr), and rsvg-convert. |
QUARTO_DENO_HEAP_MB |
Raise Deno heap for large books (e.g. 6144); indipub.sh sets a high default. |
QUARTO_DENO_V8_OPTIONS / QUARTO_DENO_EXTRA_OPTIONS |
Advanced V8 flags; see comments in books/indipub.sh (differs Quarto 1.3 vs 1.4+). |
- Per-book Node projects.
- Hand-edited
_quarto.ymlchapter lists — run each book’sscripts/update-index.sh. - Committing
_book/orpublished_books/(gitignored build artifacts).
cd books
quarto --version && python3 --version
which rsvg-convert
which lualatex && lualatex --version | head -1
./indipub.sh Networking # single book: HTML + PDF + EPUB
./indiprev.sh Networking # preview (adjust --browser on Linux/Windows)| Symptom | Likely fix |
|---|---|
| PDF hangs on “updating existing packages” | tlmgr cannot reach its repo — fix network/mirror (historic TL year if frozen). |
| PDF figures solid black | SVG used CSS var() — use literal hex (includes/diagrams/STANDARD.md). |
| PDF figures blurry | SVG used filters (feDropShadow) — remove filters for pure vector PDF. |
lualatex: command not found |
TeX bin not on PATH (see OS section). |
rsvg-convert: command not found |
Install librsvg (brew install librsvg / librsvg2-bin / MSYS2). |
| Scripts fail on Windows | Use WSL2 or Git Bash; ensure LF line endings. |
The project is designed to host and publish multiple technical books (or documentation sets) using Quarto.
/books: Book projects only (e.g.Networking,Go). Each subdir with_quarto.ymlis a book — not shared tooling./ci: CI / PDF TeX assets (TinyTeX version, package list, Font Awesome zip). Not a book./includes: Shared monorepo assets (diagram standard, analytics snippet, highlight themes). Not a book./Template: Preferred scaffold for creating new books./_archive: Legacy render scripts, old template, and retired docs (reference only)./.github: Contains GitHub Actions workflows for automated deployment.
Each book generally follows this pattern:
content/: (Expected) Contains the actual Markdown (.md) or Quarto (.qmd) source files, organized by folders (chapters/parts).scripts/:update-index.sh: A helper script that scans thecontentdirectory and automatically generates the navigation structure in_quarto.yml.
_quarto.yml: The Quarto configuration file (often generated/updated by scripts).styles/: Custom CSS/SCSS for styling the book.
The rendering process is automated via shell scripts that handle indexing, building, and aggregating output.
Run these from the books/ directory.
-
scripts/gen-portal.sh(Portal Generator):- Regenerates
published_books/index.htmland SVG book covers by scanning thepublished_books/tree. - Does not render any books — only rebuilds the portal page.
- Used by the incremental CI pipeline (
incremental.yml) after overlaying changed books. - Can also be run locally:
bash scripts/gen-portal.sh(frombooks/).
- Regenerates
-
renderpub.sh(Master Build / CI path of record):- Iterates through all subdirectories in
books/looking for_quarto.yml. - Updates Index: Calls
scripts/update-index.shfor each book to ensure the navigation reflects the latest content. - Renders: Runs
quarto renderto build HTML, PDF, and EPUB formats. - Publishes:
- Copies output to
books/published_books/. - Generates a custom SVG book cover for each book dynamically.
- Updates the main
index.htmlportal to list all rendered books.
- Copies output to
- Older full-library scripts live under
_archive/scripts/; do not use them for normal builds.
- Iterates through all subdirectories in
-
indipub.sh(Single Book Build):- Usage:
./indipub.sh <book_name> - Runs that book’s
scripts/update-index.sh(if present), thenquarto render. - Target for testing or updating a single book without rebuilding the entire library.
- Does not rebuild the portal under
published_books/.
- Usage:
-
indiprev.sh(Local Preview + Safari):- Usage:
./indiprev.sh <book> [book2 ...] [options] - HTTPS by default (
https://localhost:<port>/) because Safari often blocks plain HTTP. Uses a local self-signed cert inbooks/.preview-certs/(auto-created; gitignored). First visit: Safari may ask you to Visit Website / trust the cert once. - Default (static): HTTPS serve of each book’s
_book/(fast if already built). - Live (
--live): Quarto on an internal HTTP port + HTTPS reverse proxy on the public port. - Multi-book: ports
4242,4243, … Ctrl-C stops all.
cd books # Recommended: HTTPS static preview in Safari ./indiprev.sh Go ./indiprev.sh Go NixOS Maths # After editing content: rebuild then preview ./indipub.sh Go && ./indiprev.sh Go # Live reload over HTTPS (slower first open) ./indiprev.sh Go --live # Options ./indiprev.sh Go --port 4500 ./indiprev.sh Go --browser "Google Chrome" ./indiprev.sh Go --no-browser ./indiprev.sh Go --http # plain HTTP (not for Safari https-only) ./indiprev.sh Go --live --update-index
Flag Meaning (default) HTTPS static serve of _book/--liveQuarto live reload behind HTTPS proxy --httpPlain HTTP (skip TLS; Safari may refuse) --port <n>Public base port (default 4242)--update-indexRun scripts/update-index.shfirst--render <fmt>Only with --live(defaultnone)--browser <name>macOS app (default Safari) --no-browserServe only; print URL when ready Safari: wait for
Ready: Book -> https://localhost:…/— the script opens the tab then. On the certificate warning, continue once for localhost. Leave the terminal open. - Usage:
update-index.sh:- This is a critical utility found in most book directories.
- It reads the file system hierarchy of
content/and writes a fresh_quarto.yml, automating the tedious process of mapping files to sidebar/toc menus. - Called automatically by
indipub.shand the master render scripts; optional forindiprev.shvia--update-index.
Two workflows live under .github/workflows/:
The primary CI path. Triggers on push to main (only for changes under books/ or the workflow itself).
3-stage pipeline:
| Stage | What it does | Time |
|---|---|---|
| detect | git diff between previous and current commit to find which books/<Name>/ dirs changed |
~10 sec |
| render | Parallel matrix jobs — one per changed book. Each runs indipub.sh <Book> |
~3-5 min |
| assemble | Downloads previous gh-pages as baseline, overlays changed books, prunes deleted books, regenerates portal via gen-portal.sh, deploys |
~30 sec |
Key features:
- Incremental — a single-page edit only renders the affected book (~3-5 min total), not all 13 (~45 min).
- Parallel — multiple changed books render simultaneously (up to 4 concurrent).
- Baseline preservation — previous
gh-pagesis kept as a starting point; unchanged books are untouched. - Concurrency control — a new push cancels any in-flight run for the same branch.
- Prunes deleted books — if a book directory is removed from the repo, it's cleaned from the deployed site.
- Force rebuild — use
workflow_dispatchwith theforce_allcheckbox to rebuild everything. - Infrastructure changes (workflow file,
renderpub.sh,gen-portal.sh,Template/) trigger a full rebuild of all books automatically.
Legacy workflow, retained for manual full rebuilds of all books via workflow_dispatch.
- Trigger: Manual (
workflow_dispatch) only — push trigger is disabled. - Setup: Installs Quarto 1.3.450 and LaTeX (texlive) for PDF generation.
- Build: Executes
books/renderpub.sh(renders all books sequentially). - Deploy: Pushes
books/published_bookstogh-pages(force_orphan: true).
- Author writes content in
books/<Topic>/content. - Script (
update-index.sh) scans content tags and updates config. - Quarto builds the book from config.
- Master Script collects all builds, makes a portal page, and deployment publishes it.
Use Template (preferred). The older scaffold is preserved under _archive/templates/Template.backup/.
-
Copy the template into
books/and name the folder for the book:cp -r Template books/My-New-Book
The folder name becomes the Quarto book title when you regenerate
_quarto.yml. -
Edit content:
- Prefill lives under
content/(e.g.00-intro/,01-foundations/). - Add
.md/.qmdchapters; use numeric prefixes for order. - Optional notes go in
content/_planning/(ignored by the index script).
- Prefill lives under
-
Update configuration (do not hand-edit
_quarto.yml):cd books/My-New-Book bash scripts/update-index.sh -
Render / preview:
cd books ./indiprev.sh My-New-Book # live preview + open browser ./indipub.sh My-New-Book # one-shot render (no portal) # ./renderpub.sh # full library portal (what CI runs)