29.8  Developers Guide

This book is a software project. Every page you have read was generated from source files in a Git repository, executed by a build system, and reviewed like code — and the same machinery is open to you. This section explains how the book is put together, enough Git to participate, why we recommend working on it with a coding agent, and how to contribute a fix or an improvement. Even if you never send us a patch, this is a case study in reproducible technical writing: the problems we solve here — one source feeding many outputs, generated files, executable documents — appear in every serious ML project’s documentation and experiment repositories.

29.8.1 How the Book Is Built

29.8.1.1 One Source, Many Artifacts

Each section lives in a single Markdown file — for example, this one is chapter_appendix-tools-for-deep-learning/developers-guide.md. From these sources the build derives everything else:

chapter_*/*.md               source of truth (edit these)
├── chapter_*/*.qmd          generated Quarto input → HTML site and PDFs
├── _notebooks/<fw>/...      generated Jupyter notebooks, one per framework
│   └── outputs/...          executed outputs, committed to the repository
└── _slides/<fw>/...         generated lecture slides

Three consequences of this design are the rules that trip up newcomers:

  • Never edit generated files. A .qmd or .ipynb edit is destroyed by the next build. Edit the .md source and regenerate.
  • Framework tabs live in one file. A code block tagged %%tab pytorch appears only in the PyTorch view; an untagged Python block appears in every framework’s notebook. One source file thus yields up to four notebooks that must all execute.
  • Cell identity is stable. Every Python block carries a permanent ID (assigned by tools/add_cell_ids.py) so that slides, executed outputs, and framework views can refer to a cell across renames and moves.

Why Markdown sources instead of committing notebooks directly? Version control. A .ipynb file is JSON that entangles code with outputs, execution counts, and editor metadata, which makes diffs unreadable and code review nearly impossible. The Markdown source diffs like prose; executed outputs are stored separately (and only re-blessed when the code that produced them changes); and one file drives the website, the PDF, four notebook sets, and the slide decks without four copies drifting apart.

The d2l library you have imported all book long is generated the same way: every block marked #@save is extracted into the per-framework modules (d2l/torch.py, d2l/jax.py, …). Change the function where it is taught, rebuild, and every later chapter sees the fix — the reason those files also carry a “do not edit directly” banner.

29.8.1.2 The Repository at a Glance

d2l-neu/
├── chapter_*/            source Markdown, one directory per chapter
├── img/                  figures (SVG, generated by tools/gen_*_figures.py)
├── d2l/                  the generated d2l library
├── outputs/              committed store of executed notebook outputs
├── tools/                build scripts (preprocessing, notebooks, slides)
├── Makefile              entry point: make html, make slides, make lib ...
└── CLAUDE.md             build documentation, written for coding agents

make html renders the site from committed outputs on any laptop — no GPU required; executing notebooks that need accelerators is a separate, explicit step. The Makefile and CLAUDE.md document every target.

29.8.2 Git in Five Minutes

If you already use Git daily, skip ahead. Otherwise, the six commands below are most of what contributing requires. First, make your own copy: click Fork on the repository page, then

git clone https://github.com/<your-username>/d2l-neu.git
cd d2l-neu
git switch -c fix-typo-in-attention    # a branch per change

Edit the source .md file, then record and publish the change:

git status                  # what changed?
git diff                    # show the exact edits
git add chapter_attention-mechanisms/attention.md
git commit -m "Fix transposed subscript in attention equation"
git push -u origin fix-typo-in-attention

GitHub will offer to open a pull request — your branch, proposed for merging, with a diff the maintainers can review and comment on. (The gh command-line tool does the same with gh pr create.) Small, focused pull requests get reviewed quickly; “fixed one equation” merges in a day, “rewrote three chapters” invites a long conversation. This fork-branch-PR loop is the collaboration pattern of essentially all open source, so time spent learning it here repays itself far beyond this book.

29.8.3 Working with a Coding Agent

The single best piece of practical advice in this section: work on the book — and on your own notebook projects — with a coding agent (Claude Code, Codex, Gemini CLI, and peers). This repository is deliberately agent-friendly, and the reasons illustrate what makes any project agent-friendly:

  • The build is self-describing. CLAUDE.md tells an agent how to regenerate, execute, and render everything. Documentation written for agents turns out to be excellent documentation for humans, and vice versa.
  • Verification is executable. The definition of “this edit works” is mechanical: the notebook executes top to bottom in all frameworks, the linter passes, the page renders. An agent can run that whole loop — edit, regenerate, execute, inspect the failure, fix — dozens of times while you review only the final diff.
  • The tedious parts are mechanical. Keeping four framework implementations in sync, checking that every :numref: resolves, regenerating figures: exactly the multi-file consistency work agents do well and humans do grudgingly.

A workflow that works in practice: describe the change at the level of intent (“the momentum notebook’s contour plot mislabels the axes; fix it and re-run the affected notebooks”), let the agent locate sources, edit, and verify, and then review the diff yourself — you are the author of anything you submit, and agents inherit your responsibility, not the reverse. Two cautions from experience. Agents share the newcomer failure mode of editing generated files unless the project documentation warns them (ours does). And an agent eager to make a failing check pass may weaken the check or the code instead of fixing the cause — “the notebook now runs” is not the same as “the notebook still teaches the right thing.” Review accordingly.

29.8.4 Contributing Your Changes

Found a typo, a broken link, or an explanation that reads worse than it should? Contributions are welcome, and readers’ pull requests have improved every chapter of this book. In rough order of effort:

  • Small text fixes. For a one-line fix you do not even need a local checkout: open the source file on GitHub, press the edit (pencil) button, and GitHub walks you through fork, commit, and pull request in the browser.
  • Code and content changes. Clone, branch, edit the source .md, and verify before submitting: regenerate the affected notebooks and run them end to end (with an agent, this is one instruction), and render the page with make html to check formatting, references, and figures. If you edit code that carries #@save, rebuild the library (make lib) and expect downstream notebooks to be affected.
  • Working in the notebook view. If you prefer editing in Jupyter or VS Code rather than raw Markdown, this repository ships a VS Code extension (under .vscode-extension/) built for exactly that: it opens the generated notebook for any section with the right kernel preselected, switches between the PyTorch/TensorFlow/JAX/MXNet views of the same source, previews the section’s slide deck live, and syncs edits from the notebook back into the Markdown source so that generated files never become the thing you edited. make kernels registers the per-framework Jupyter kernels it uses.

Whatever the route, the review bar is the one this chapter has been teaching throughout: the change executes cleanly from a fresh state, in every framework it touches, and the source of truth — never a generated artifact — is what changed.

29.8.5 Summary

  • One Markdown source generates the website, PDFs, per-framework notebooks, executed outputs, slides, and the d2l library; generated files are never edited directly.
  • Markdown-as-source exists for version control: readable diffs and reviewable pull requests are what make a 250-notebook book maintainable.
  • The contribution loop is fork → branch → edit source → verify (execute notebooks, render) → small pull request.
  • Coding agents fit this workflow unusually well because the build is self-describing and verification is executable — but you review and own what you submit.
  • The VS Code extension bridges notebook-style editing and Markdown-source truth: framework views, slide preview, and sync-back.

29.8.6 Exercises

  1. Fork the repository, run make html, and render the book locally. How long does a no-op rebuild of one page take?
  2. Find the #@save block that defines a d2l function you have used, change its docstring, rebuild the library, and verify the change is visible from a notebook import.
  3. Use a coding agent for a real micro-contribution: have it find a typo or broken link in a chapter of your choice, fix the source, and verify the render — then review its diff as if you were the maintainer.
  4. Open the generated PyTorch and JAX notebooks of one section side by side (the VS Code extension makes this two keystrokes). What exactly differs, and where does that difference live in the source file?