Colophon

ZigZag was written in public, one conversation at a time. Here’s what was on the workbench.

The stack

Tool Version What it does here
Zig 0.15.2 The language being learned
Claude Code 2.1.71 AI coding agent — the other half of the conversation
Claude Opus 4.6 claude-opus-4-6 The model behind the agent
Quarto 1.8.27 Turns .qmd files into the book you’re reading
Python 3.13 Required by Quarto’s Jupyter engine (not by choice)
uv Keeps Python contained in a project-local venv
Note

These are the versions at the start of the project (March 2026). Things will update as the book grows. If a version change matters — if Zig ships a breaking release or Quarto changes how code blocks work — I’ll note it in the relevant chapter.

How the pieces fit together

Claude Code runs in a terminal. It reads files, writes files, runs commands, and holds a conversation while doing all of that. The model powering it — Claude Opus 4.6 — is what actually generates the responses, writes the code, and occasionally goes on philosophical tangents that I choose not to rein in.

Quarto takes the .qmd chapter files (Markdown with some extensions) and renders them into the HTML site you’re reading. Code output is real — generated by actually running zig run at render time, then frozen into the page via Quarto’s freeze: auto feature. CI deploys the frozen results without needing Zig or Python installed.

Zig is Zig. A single binary. No runtime. The entire toolchain fits in a folder you can move around. The compiler, the build system, the test runner — it’s all one thing. We’ll talk about why that matters.

The process

  1. Open Claude Code in the project directory
  2. Have a conversation about a Zig concept
  3. Write and run code during the conversation
  4. Save the session log to sessions/
  5. Turn the interesting parts into a chapter
  6. quarto render to build the book
  7. Repeat

That’s the whole pipeline. CI handles the rest — a GitHub Actions workflow renders the frozen book and deploys to GitHub Pages.

↯ The Python situation

This Zig book requires Python. Not for anything Zig-related — Quarto uses Jupyter to execute code blocks, and Jupyter is Python.

Quarto itself is a rendering engine. It doesn’t bundle Jupyter — when it encounters an executable {python} cell, it hands it off to Jupyter to run. So the execution chain is: Quarto → Jupyter → Python → subprocess.runzig run. Without Jupyter installed, Quarto errors on every executable cell.

The natural approach would be to use Jupyter’s bash_kernel to run shell commands directly, cutting Python out of the chain. On Windows, that kernel depends on pexpect, which needs Unix pseudo-terminals, so it doesn’t work. The workaround: each executable block uses a hidden Python cell (#| echo: false) that calls subprocess.run to invoke zig run. The rendered output shows only the Zig command and its result.

Here’s the local setup:

# Create a project-local venv
uv venv

# Install Jupyter (~90 packages)
uv pip install jupyter

# Tell Quarto where to find Python
# Windows doesn't auto-detect .venv — set QUARTO_PYTHON
export QUARTO_PYTHON=".venv/Scripts/python.exe"  # or bin/python on Unix

# Render — code blocks execute, output gets frozen
quarto render

The freeze: auto setting in _quarto.yml caches execution results in _freeze/, which gets committed to git. After that, CI only needs Quarto to render the book — no Python, no Jupyter, no Zig. A .env file at the project root sets QUARTO_PYTHON so you don’t have to export it every time.

One-time setup: uv venv && uv pip install jupyter. Then you don’t think about it again.