# The Template Textbook — Modular, Fillable Book Scaffold A domain-neutral exemplar that demonstrates the **book-length manuscript** shape for this research-template monorepo: a data-driven manuscript (parts → chapters → labs → question banks), a tested computational backbone under `src/`, deterministic figure and diagram generators, and a content scaffold/validation engine that lets a future author fill marked stubs out to hundreds or thousands of pages without drifting from the structural contract. Everything downstream — the table of contents, chapter auto-numbering, figure generation, lab/question wiring, and the manuscript-integrity tests — reads a single source of truth: [`manuscript/config.yaml`](manuscript/config.yaml). To grow the book you edit that file, then run a thin orchestrator that materialises the missing stub files in the correct shape. The config boundary is validated before filesystem work begins. `units:` wins over the legacy `parts:` alias even when explicitly empty; part directories and chapter/intro filenames must be relative, portable, single-level Markdown paths; path traversal, absolute paths, malformed entries, and duplicate source paths fail the gate rather than being interpreted by a scaffold or renderer. ## When to use this template Use this template for **book-length manuscripts**: parts → chapters → labs → question banks declared in a single `config.yaml`, with auto-numbering, deterministic figure/diagram generation, and structural-contract tests that keep hundreds of pages from drifting. For a single-paper computational project see [`template_code_project`](../template_code_project/); for editorial/prose review see [`template_prose_project`](../template_prose_project/). Full roster: [`projects/AGENTS.md`](../../AGENTS.md#permanent-canonical-exemplars). ## Publication and rendering The publishing metadata and per-platform status below are **compiled from `manuscript/config.yaml`** by `infrastructure.publishing.status_report` — do not hand-edit between the markers; update the config and regenerate (see the legend). **template_textbook** · Daniel Ari Friedman Concept DOI: [10.5281/zenodo.20533125](https://doi.org/10.5281/zenodo.20533125) | Version DOI: [10.5281/zenodo.20932112](https://zenodo.org/records/20932112) | Repository: [docxology/template_textbook](https://github.com/docxology/template_textbook) Publishing surface — 20 platforms, 9 published: | Platform | Tier | Status | Reference | Credentials | | --- | --- | --- | --- | --- | | zenodo | first-class | ✅ published | [10.5281/zenodo.20533125](https://doi.org/10.5281/zenodo.20533125) | `ZENODO_API_TOKEN` | | github | first-class | ✅ published | [docxology/template_textbook](https://github.com/docxology/template_textbook) | `GITHUB_TOKEN` | | arxiv | first-class | ⚪ available | — | — | | pypi | first-class | ✅ published | [https://test.pypi.org/project/template-textbook/0.1.2/](https://test.pypi.org/project/template-textbook/0.1.2/) | `PYPI_TOKEN`, `TESTPYPI_TOKEN` | | ipfs_pinata | first-class | ✅ published | [https://gateway.pinata.cloud/ipfs/QmaTFtcxkdPJGC3HHWVCkQQC81SYTD8Ninu2BB9KxiHxEN](https://gateway.pinata.cloud/ipfs/QmaTFtcxkdPJGC3HHWVCkQQC81SYTD8Ninu2BB9KxiHxEN) | `PINATA_JWT` | | ipfs_web3storage | first-class | ⚪ available | — | `WEB3_STORAGE_TOKEN` | | software_heritage | first-class | ✅ published | [https://archive.softwareheritage.org/browse/origin/?origin_url=https://github.com/docxology/template_textbook](https://archive.softwareheritage.org/browse/origin/?origin_url=https://github.com/docxology/template_textbook) | — | | github_pages | first-class | ✅ published | [https://docxology.github.io/template_textbook/](https://docxology.github.io/template_textbook/) | `GITHUB_TOKEN` | | cloudflare_pages | first-class | ⚪ available | — | `CLOUDFLARE_API_TOKEN` | | netlify | first-class | ✅ published | [https://6a4443ae4a7a3eb5dba63532--tranquil-kleicha-0c9203.netlify.app](https://6a4443ae4a7a3eb5dba63532--tranquil-kleicha-0c9203.netlify.app) | `NETLIFY_AUTH_TOKEN` | | huggingface_hub | first-class | ✅ published | [https://huggingface.co/datasets/ActiveInference/template_textbook](https://huggingface.co/datasets/ActiveInference/template_textbook) | `HUGGINGFACE_TOKEN`, `HF_TOKEN` | | osf | first-class | ✅ published | [https://osf.io/8kg5z/](https://osf.io/8kg5z/) | `OSF_TOKEN` | | amazon_kdp | documented | 🟡 planned | — | `AMAZON_KDP_EMAIL`, `AMAZON_KDP_PASSWORD` | | google_play_books | documented | 🟡 planned | — | `GOOGLE_PLAY_BOOKS_SERVICE_ACCOUNT_JSON` | | gumroad | documented | 🟡 planned | — | `GUMROAD_ACCESS_TOKEN` | | leanpub | documented | 🟡 planned | — | `LEANPUB_API_KEY` | | lulu | documented | 🟡 planned | — | `LULU_CLIENT_KEY`, `LULU_CLIENT_SECRET` | | draft2digital | documented | 🟡 planned | — | `DRAFT2DIGITAL_API_TOKEN` | | stripe | documented | 🟡 planned | — | `STRIPE_SECRET_KEY`, `STRIPE_PUBLISHABLE_KEY` | | ingramspark | documented | 🟡 planned | — | `INGRAMSPARK_CLIENT_ID`, `INGRAMSPARK_CLIENT_SECRET` | _Status legend: ✅ published (durable identifier recorded in `config.yaml`) · 🔵 reserved (identifier reserved but not yet registered by final publication) · ⚪ available (adapter implemented and locally verifiable) · 🟡 planned. This block is generated — edit `manuscript/config.yaml`, then regenerate with `uv run python -m infrastructure.publishing.status_report --project --write`._ The 3 platforms still shown ⚪ available are not automatable to "published" with current tooling/credentials, not an oversight: **arXiv** has no submission API in this codebase (`infrastructure.publishing.arxiv` only prepares a local tarball — a human must upload it via arxiv.org and the resulting `arxiv` URL would then be added to `publication.published_artifacts`); **Cloudflare Pages** needs a `CLOUDFLARE_ACCOUNT_ID` the configured API token cannot auto-discover; **IPFS (Web3.Storage)** has no `WEB3_STORAGE_TOKEN` configured. - Canonical renderer: [docxology/template](https://github.com/docxology/template) with `--project templates/template_textbook` - Tracked outputs: [`output/`](output/) in this project and `output/templates/template_textbook/` in the monorepo; public output files above 50 MB stay out of git. To regenerate this exemplar from the public monorepo: ```bash git clone https://github.com/docxology/template cd template uv sync ./run.sh --project templates/template_textbook --pipeline --core-only uv run python scripts/pipeline/stage_04_validate.py --project templates/template_textbook uv run python scripts/pipeline/stage_05_copy.py --project templates/template_textbook ``` Standalone repositories are publication mirrors for source, DOI metadata, and tracked rendered artifacts. Use the monorepo above when you need the full shared infrastructure, pipeline stages, or cross-template validation. ## What this template is - **Modular.** Structure is declared in YAML, not hand-numbered. Add a part or a chapter in `config.yaml` and the numbering, TOC labels, lab, and question bank all follow. - **Fillable.** Every generated chapter ships as a structurally-complete stub: labelled headings, a figure with alt text, a Study Blueprint, Learning Objectives, a worked formalism (equation + parameter table), an inline Mermaid diagram, and Summary / Key Terms / Further Reading / Practice sections. An author fills the prose between the markers. - **Reproducible.** Figures and diagrams come from deterministic Python (fixed seeds, headless matplotlib). The same inputs always produce the same outputs. - **Tested.** The computational backbone and the structural contract are both enforced by a no-mocks test suite at ≥90% coverage. ## Directory map ``` template_textbook/ ├── manuscript/ │ ├── config.yaml # SINGLE SOURCE OF TRUTH (parts → chapters) │ ├── references.bib # citation keys ([@key] must resolve here) │ ├── glossary.md # glossary anchors ([**term**](#gl:anchor)) │ ├── part_0/ … part_III/ # one .md per chapter; parts & chapters declared in config.yaml │ ├── labs// # one lab per chapter (lab_.md) │ ├── questions// # one question bank per chapter (q_.md) │ ├── appendices/ # reference appendices │ └── assets/ # cover and static assets ├── src/ │ ├── textbook/ # config, toc, content engine, constants, models │ ├── visualization/ # deterministic matplotlib figures │ ├── mermaid/ # Mermaid sources (PNG or .mmd fallback) │ └── textbook_*.py # paths, io, logging, visuals utilities ├── scripts/ # thin orchestrators (figures, diagrams, analysis, scaffold, audit) ├── tests/ # no-mocks suite incl. test_manuscript_integrity.py └── pyproject.toml # project config (90% coverage gate) ``` The four parts are: **Part 0** Orientation and Methods, **Part I** Fundamentals, **Part II** Core Systems, **Part III** Applications and Synthesis — twelve chapters in all. ## Quick start All commands assume `uv` (never `pip`/`npm`). Run them from the monorepo root. ```bash # 1. Install dependencies for the workspace uv sync # 2. Materialise any missing stub files declared in config.yaml uv run python projects/templates/template_textbook/scripts/scaffold_chapter.py # 3. Generate deterministic figures and diagrams uv run python projects/templates/template_textbook/scripts/generate_figures.py uv run python projects/templates/template_textbook/scripts/generate_diagrams.py # 4. Run the test suite with coverage (must collect >0 tests, ≥90% coverage) # From the monorepo root, `dev` is a default dependency-group (plain `uv run`); # the `--extra dev` form only works from inside the project dir. uv run python -m pytest projects/templates/template_textbook/tests/ \ --cov=projects/templates/template_textbook/src --cov-fail-under=90 # 5. Audit scaffold structure (default mode reports but allows stub markers) uv run python projects/templates/template_textbook/scripts/audit_textbook_quality.py # Before calling a filled fork complete, require zero stubs in audited sections uv run python projects/templates/template_textbook/scripts/audit_textbook_quality.py --require-complete ``` > Exit code 0 alone is not proof: confirm the suite collected more than zero > tests and that coverage met the floor. The default audit proves scaffold > structure; `--require-complete` is the explicit filled-manuscript gate. ## How to grow the book The workflow is always **edit config, then scaffold**: 1. Open [`manuscript/config.yaml`](manuscript/config.yaml) and add a chapter under the relevant part (a `file:` + `title:` entry), or add a whole new part with its `id`, `title`, `label`, `directory`, and `chapters`. 2. Run `scripts/scaffold_chapter.py`. It reads the config and writes any missing chapter, lab, and question-bank stub in the contract-compliant shape. Existing files are left untouched. 3. Fill the prose between the stub markers (``, `TODO:`, `TKTK`). Keep the labelled headings, the figure/equation/table cross-references, and the curriculum scaffold intact. 4. Regenerate figures/diagrams if you added new ones, then run the tests and the structural audit. Once every audited section is filled, also run the audit with `--require-complete`; it reports each section's stub count and fails until the total reaches zero. Because structure is declared once in YAML, the book can scale from this 12-chapter skeleton to an arbitrarily large work without renumbering anything by hand. ## The design in one paragraph `config.yaml` declares the structure. `src/textbook/` turns that declaration into numbering (`toc.py`), validation and scaffolding (`content.py`), the structural contract (`constants.py`), and worked formalisms (`models.py`). `scripts/` are **thin orchestrators**: they import tested methods from `src/`, handle I/O and visualization, and never implement business logic themselves. `tests/` enforce both the math and the manuscript contract with real data and no mocks. ## Documentation map | Document | Read it for | | --- | --- | | **This file (`README.md`)** | Overview, directory map, quick-start commands, how to grow the book | | [`AGENTS.md`](AGENTS.md) | Agent-facing reference: invariants, editing checklist, frozen vs. fillable files | | [`manuscript/config.yaml`](manuscript/config.yaml) | The single source of truth for book structure | | Monorepo [`README.md`](https://github.com/docxology/template/blob/main/README.md) / [`CLAUDE.md`](https://github.com/docxology/template/blob/main/CLAUDE.md) / [`AGENTS.md`](https://github.com/docxology/template/blob/main/AGENTS.md) | Pipeline semantics, CI parity, two-layer architecture | ## Worked exemplars vs. stubs Two chapters are filled to completion as **finished-prose references** — copy their shape when filling the rest: - [`manuscript/part_I/first_principles.md`](manuscript/part_I/first_principles.md) — a *model-derivation* chapter (logistic growth, worked numbers from `textbook.models`). - [`manuscript/part_III/case_studies.md`](manuscript/part_III/case_studies.md) — a *data-driven case study* (grouping, a fit, and honest limits). Every other chapter ships as a structurally-complete **stub** (marked with `` / `TODO:`). The appendices [`appendix_format_gallery.md`](manuscript/appendices/appendix_format_gallery.md) and [`appendix_formalisms.md`](manuscript/appendices/appendix_formalisms.md) demonstrate every content primitive and every formal element. ## Output formats The book renders to **PDF, HTML, EPUB, and DOCX** (`render.formats` in `config.yaml`). Diagrams embed as images when a Chrome binary is reachable by `mmdc` (see [`docs/visualization_guide.md`](docs/visualization_guide.md)). ## License Dual-licensed: **code** (`src/`, `scripts/`, `tests/`) under **Apache-2.0** ([`LICENSE`](LICENSE)); **manuscript content** (`manuscript/`) under **CC BY 4.0** ([`LICENSE-CONTENT.md`](LICENSE-CONTENT.md)). See also [`CHANGELOG.md`](CHANGELOG.md). ## Template integrity - Forward backlog: [`TODO.md`](TODO.md). - Copy-and-customize config: [`manuscript/config.yaml.example`](manuscript/config.yaml.example). - Project validation: `uv run pytest projects/templates/template_textbook/tests/ --cov=projects/templates/template_textbook/src --cov-fail-under=90`. - Repo drift validation: `uv run python scripts/audit/check_template_drift.py --strict`. ## Directory & sub-document map Navigation links to in-tree documents (keeps them discoverable): - [src/ — agent notes](src/AGENTS.md)