{"id":50537164,"url":"https://github.com/lymanepp/book-tools","last_synced_at":"2026-06-03T17:30:32.067Z","repository":{"id":352247065,"uuid":"1213588006","full_name":"lymanepp/book-tools","owner":"lymanepp","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-29T22:18:06.000Z","size":167,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-29T23:20:05.293Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lymanepp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-17T14:40:18.000Z","updated_at":"2026-05-29T22:18:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lymanepp/book-tools","commit_stats":null,"previous_names":["lymanepp/book-tools"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lymanepp/book-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lymanepp%2Fbook-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lymanepp%2Fbook-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lymanepp%2Fbook-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lymanepp%2Fbook-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lymanepp","download_url":"https://codeload.github.com/lymanepp/book-tools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lymanepp%2Fbook-tools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33876327,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-03T17:30:31.970Z","updated_at":"2026-06-03T17:30:32.047Z","avatar_url":"https://github.com/lymanepp.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unified Book Build Ecosystem\n\n## How to share the scripts without keeping two copies\n\nThe scripts directory is the single source of truth. The question is how\nit reaches both book repos without copying it. There are three options.\nThe recommendation is at the top.\n\n---\n\n### Option 1 — Git submodule (recommended)\n\nCreate a third repository: `book-tools`. It contains only the `scripts/`\ndirectory and `.devcontainer/`. Both book repos (`what-scripture-says` and\nthe counseling repo) add it as a submodule pinned to a specific commit.\n\n**Repo layout:**\n\n```\nbook-tools/                 ← shared repo (this directory)\n  scripts/\n    build-template.py\n    postprocess-pandoc.py\n    docx.sh\n    mdformat.lua\n    md2ssml.lua\n    epub.sh\n    docx2pdf.py\n    docx2pdf.sh\n    download\n    Makefile.book\n  .devcontainer/\n    devcontainer.json\n    post-create\n\nwhat-scripture-says/        ← your existing repo\n  scripts/                  ← submodule pointing to book-tools/scripts/\n  book1/\n    book.env\n    front-matter-print.md\n    front-matter-submission.md\n    metadata-print.yaml\n    metadata-submission.yaml\n    header.tex\n    Makefile                ← copy of Makefile.book (or symlink)\n    00-introduction.md\n    01-*.md ...\n  book2/\n    (same layout as book1)\n  .devcontainer/ → submodule or copy of book-tools/.devcontainer/\n  .github/workflows/build-books.yml\n\ncounseling-book/            ← your wife's existing repo\n  scripts/                  ← same submodule, same commit\n  counseling/\n    book.env\n    front-matter-print.md\n    front-matter-submission.md\n    metadata-print.yaml\n    metadata-submission.yaml\n    header.tex              ← if PDF output is needed; omit otherwise\n    Makefile                ← copy of Makefile.book\n    ch00-10-preface.md      ← rename to 00-preface.md (see Markdown changes)\n    ch01-*.md ...           ← rename to 01-*.md etc.\n  .devcontainer/ → submodule or copy\n  .github/workflows/build-books.yml\n```\n\n**Setup (one time per consuming repo):**\n\n```bash\n# Inside what-scripture-says or counseling-book:\ngit submodule add https://github.com/you/book-tools scripts\ngit submodule update --init --recursive\n```\n\n**Updating the scripts:**\n\n```bash\n# Inside book-tools:\ngit commit -am \"fix: table width clamping for 4-col tables\"\ngit push\n\n# Inside each consuming repo — update the pinned commit:\ncd scripts \u0026\u0026 git pull origin main \u0026\u0026 cd ..\ngit add scripts\ngit commit -m \"chore: update book-tools submodule\"\ngit push\n```\n\n**Why submodule instead of subtree:**\nSubtree embeds the scripts history into the consuming repo, making it\nimpossible to pull changes selectively. Submodule keeps them separate\nand pinned — a script change does not silently affect a book build until\nyou explicitly update the pin.\n\n**CI:**\nThe workflow file included in this directory uses `submodules: true` on\nthe checkout step. That is the only CI change required.\n\n**VS Code devcontainer:**\nBoth repos' `.devcontainer/` directories can themselves be submodules of\n`book-tools/.devcontainer/`, or simply copied once and kept in sync\nmanually (the devcontainer changes rarely).\n\n---\n\n### Option 2 — Monorepo\n\nCombine everything into one repository:\n\n```\nepp-books/\n  scripts/          ← one copy, shared by all books\n  .devcontainer/\n  .github/workflows/build-books.yml\n  book1/\n  book2/\n  counseling/\n```\n\n**Advantages:** Dead simple. One `git clone`, one CI job, no submodule\nmechanics, no pinning.\n\n**Disadvantages:** Your wife's counseling book is in your repo (or vice\nversa). Commit history is interleaved. Access control is all-or-nothing.\nIf either of you ever publishes to a platform that expects a clean repo\nper book, you're restructuring later.\n\nUse this if access and history separation are not concerns and you want\nthe simplest possible setup.\n\n---\n\n### Option 3 — Package install (overkill for now)\n\nPublish `book-tools/scripts/` as a Python package to PyPI or a private\nindex. Each repo installs it via `pip install book-tools==x.y.z`. This\nis the correct answer for a team of ten. For two authors it is not worth\nthe overhead.\n\n---\n\n## What is in scripts/\n\n| File | Purpose |\n|---|---|\n| `build-template.py` | Builds `reference-template.docx` from pandoc's default seed. Run automatically by `docx.sh` before every print build. |\n| `postprocess-pandoc.py` | Injects running headers/footers, wires sections, splits chapter headings, fixes blockquote styles, processes copyright page, normalises fonts, lays out all tables. |\n| `docx.sh` | Main build driver. Sources `book.env`, renders front matter, calls pandoc, calls postprocessor. Accepts `print` (default) or `submission`. |\n| `mdformat.lua` | Pandoc Lua filter. Maps `\\newpage` → odd-page section break (DOCX) / `\\newpage` (LaTeX) / CSS page break (EPUB/HTML). Maps `\\toc` → native Word TOC field. |\n| `md2ssml.lua` | Pandoc Lua filter for SSML (audiobook/TTS) output. |\n| `epub.sh` | Builds a full-book EPUB from submission front matter. Strips LaTeX commands and footnotes for TTS compatibility. |\n| `docx2pdf.py` | Windows-only: converts DOCX to PDF via Word COM automation. |\n| `docx2pdf.sh` | Wrapper for `docx2pdf.py` using the `py` launcher. |\n| `download` | Downloads the latest CI artifact and converts to PDF. |\n| `Makefile.book` | Per-book Makefile for PDF/EPUB/SSML targets. Copy to each book directory as `Makefile`. |\n\n---\n\n## Required per-book files (not in scripts/)\n\nEach book directory must contain:\n\n```\nbook.env                    ← identity and ISBNs\nfront-matter-print.md       ← title page, copyright, \\toc marker\nfront-matter-submission.md  ← minimal front matter for submission\nmetadata-print.yaml         ← pandoc metadata for print build\nmetadata-submission.yaml    ← pandoc metadata for submission build\nheader.tex                  ← LaTeX header (ragged right, microtype, em-dash)\nMakefile                    ← copy of scripts/Makefile.book\nNN-chapter-name.md          ← chapter files (must match [0-9][0-9]-*.md)\n```\n\n---\n\n## Markdown changes required when adopting the unified ecosystem\n\n### Counseling book chapters\n\n**1. Rename chapter files.**\nThe `docx.sh` glob is `[0-9][0-9]-*.md`. Counseling files use\n`chNN-NN-title.md`. Rename to `NN-title.md`:\n\n```\nch00-10-preface.md       → 00-preface.md\nch01-governing-framework.md → 01-governing-framework.md\n```\n\n**2. Replace implicit H2 page breaks with explicit `\\newpage` or `\\pagebreak`.**\nThe counseling book's old `content-layout.lua` injected a page break\nbefore every H2 automatically. The unified `mdformat.lua` does not —\nbreaks are explicit. For a chapter that starts on an odd page (which\nall chapters should), prefix the H1 with `\\newpage`. For a section\nheading within a chapter that should start on a new page (not\nodd-page), use `\\pagebreak`:\n\n```markdown\n\\newpage\n\n# Chapter 1: The Governing Framework\n\n...body...\n\n\\pagebreak\n\n## The Three-Domain Model\n```\n\nIf a section heading should not force a page break (most of them\nshould not), add no marker — the H2 spacing handles visual separation.\n\n**3. Scripture quotations — use fenced div for `Scripture Quote` style.**\nPandoc maps bare `\u003e` blockquotes to the `Block Text` style in DOCX. `Block\nText` is styled with a shaded background and left accent border — appropriate\nfor general prose citations. Scripture quotations should use the fenced div\nform to get the distinct `Scripture Quote` style:\n\n```markdown\n::: {custom-style=\"Scripture Quote\"}\n\u003e For God so loved the world… (John 3:16)\n:::\n```\n\nLeave bare `\u003e` for non-scripture quotations. This is a per-instance change.\n\n**4. Add `book.env`.**\nCreate `counseling/book.env`:\n\n```bash\nBOOK_TITLE='Counseling Toward Wholeness'\nBOOK_SUBTITLE='A Practitioner'\\''s Theological Framework'\nBOOK_OUTPUT_BASENAME='counseling-toward-wholeness'\n```\n\n### Scripture book chapters\n\nNo changes required. The Scripture books already use explicit `\\newpage`\nmarkers (which produce odd-page section breaks, as before) and the correct\n`NN-*.md` filename convention. The `\\pagebreak` command is now also\navailable for intra-chapter plain page breaks if ever needed.\n\nBare `\u003e` blockquotes in Scripture chapters land in `Block Text` (shaded,\nleft border, italic). If you want them in `Scripture Quote` style instead,\nwrap with the fenced div. If the current rendering is acceptable, no change.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flymanepp%2Fbook-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flymanepp%2Fbook-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flymanepp%2Fbook-tools/lists"}