bookforge-kdp 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. bookforge_kdp-0.2.0/LICENSE +21 -0
  2. bookforge_kdp-0.2.0/PKG-INFO +509 -0
  3. bookforge_kdp-0.2.0/README.md +445 -0
  4. bookforge_kdp-0.2.0/pyproject.toml +82 -0
  5. bookforge_kdp-0.2.0/setup.cfg +4 -0
  6. bookforge_kdp-0.2.0/src/bookforge/__init__.py +9 -0
  7. bookforge_kdp-0.2.0/src/bookforge/assemble.py +302 -0
  8. bookforge_kdp-0.2.0/src/bookforge/callouts.py +121 -0
  9. bookforge_kdp-0.2.0/src/bookforge/cli.py +182 -0
  10. bookforge_kdp-0.2.0/src/bookforge/config.py +474 -0
  11. bookforge_kdp-0.2.0/src/bookforge/covers.py +410 -0
  12. bookforge_kdp-0.2.0/src/bookforge/deps.py +35 -0
  13. bookforge_kdp-0.2.0/src/bookforge/diagrams.py +342 -0
  14. bookforge_kdp-0.2.0/src/bookforge/epub.py +80 -0
  15. bookforge_kdp-0.2.0/src/bookforge/errors.py +23 -0
  16. bookforge_kdp-0.2.0/src/bookforge/package.py +139 -0
  17. bookforge_kdp-0.2.0/src/bookforge/pdf.py +143 -0
  18. bookforge_kdp-0.2.0/src/bookforge/raster.py +88 -0
  19. bookforge_kdp-0.2.0/src/bookforge/scaffold/.gitignore +3 -0
  20. bookforge_kdp-0.2.0/src/bookforge/scaffold/assets/README.md +16 -0
  21. bookforge_kdp-0.2.0/src/bookforge/scaffold/assets/author/README.md +2 -0
  22. bookforge_kdp-0.2.0/src/bookforge/scaffold/assets/cover/README.md +3 -0
  23. bookforge_kdp-0.2.0/src/bookforge/scaffold/assets/diagrams/README.md +4 -0
  24. bookforge_kdp-0.2.0/src/bookforge/scaffold/book.yaml +63 -0
  25. bookforge_kdp-0.2.0/src/bookforge/scaffold/build.bat +84 -0
  26. bookforge_kdp-0.2.0/src/bookforge/scaffold/build.sh +65 -0
  27. bookforge_kdp-0.2.0/src/bookforge/scaffold/content/back/about-notes.md +6 -0
  28. bookforge_kdp-0.2.0/src/bookforge/scaffold/content/chapters/ch01-first-chapter.md +27 -0
  29. bookforge_kdp-0.2.0/src/bookforge/scaffold/content/chapters/ch02-second-chapter.md +5 -0
  30. bookforge_kdp-0.2.0/src/bookforge/scaffold/content/front/preface.md +5 -0
  31. bookforge_kdp-0.2.0/src/bookforge/studio/__init__.py +56 -0
  32. bookforge_kdp-0.2.0/src/bookforge/studio/app.py +1114 -0
  33. bookforge_kdp-0.2.0/src/bookforge/studio/static/app.js +964 -0
  34. bookforge_kdp-0.2.0/src/bookforge/studio/static/index.html +390 -0
  35. bookforge_kdp-0.2.0/src/bookforge/studio/static/style.css +650 -0
  36. bookforge_kdp-0.2.0/src/bookforge/templates/epub.css +82 -0
  37. bookforge_kdp-0.2.0/src/bookforge/templates/interior.css +345 -0
  38. bookforge_kdp-0.2.0/src/bookforge/typography.py +33 -0
  39. bookforge_kdp-0.2.0/src/bookforge/verify.py +184 -0
  40. bookforge_kdp-0.2.0/src/bookforge/watch.py +74 -0
  41. bookforge_kdp-0.2.0/src/bookforge_kdp.egg-info/PKG-INFO +509 -0
  42. bookforge_kdp-0.2.0/src/bookforge_kdp.egg-info/SOURCES.txt +50 -0
  43. bookforge_kdp-0.2.0/src/bookforge_kdp.egg-info/dependency_links.txt +1 -0
  44. bookforge_kdp-0.2.0/src/bookforge_kdp.egg-info/entry_points.txt +2 -0
  45. bookforge_kdp-0.2.0/src/bookforge_kdp.egg-info/requires.txt +17 -0
  46. bookforge_kdp-0.2.0/src/bookforge_kdp.egg-info/top_level.txt +1 -0
  47. bookforge_kdp-0.2.0/tests/test_assemble.py +154 -0
  48. bookforge_kdp-0.2.0/tests/test_config.py +264 -0
  49. bookforge_kdp-0.2.0/tests/test_covers_and_toc.py +201 -0
  50. bookforge_kdp-0.2.0/tests/test_studio_api.py +374 -0
  51. bookforge_kdp-0.2.0/tests/test_studio_packaging.py +114 -0
  52. bookforge_kdp-0.2.0/tests/test_studio_picker.py +153 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pushkar Mishra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,509 @@
1
+ Metadata-Version: 2.4
2
+ Name: bookforge-kdp
3
+ Version: 0.2.0
4
+ Summary: Turn a book.yaml file and a folder of markdown into a KDP-ready paperback PDF, a validated EPUB3, and both covers. Requires pandoc and epubcheck on PATH.
5
+ Author: Pushkar Mishra
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Pushkar Mishra
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/pushkar-mishra/BookForge
29
+ Project-URL: Repository, https://github.com/pushkar-mishra/BookForge
30
+ Project-URL: Issues, https://github.com/pushkar-mishra/BookForge/issues
31
+ Keywords: kdp,epub,epub3,self-publishing,amazon-kdp,pandoc,book,publishing,pdf
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Other Audience
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Programming Language :: Python :: 3.13
42
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
43
+ Classifier: Topic :: Text Processing :: Markup :: reStructuredText
44
+ Classifier: Topic :: Software Development :: Build Tools
45
+ Requires-Python: >=3.10
46
+ Description-Content-Type: text/markdown
47
+ License-File: LICENSE
48
+ Requires-Dist: pyyaml>=6.0
49
+ Requires-Dist: pypdf>=4.0
50
+ Requires-Dist: weasyprint>=61.0
51
+ Requires-Dist: pillow>=10.0
52
+ Requires-Dist: pypdfium2>=4.25
53
+ Provides-Extra: studio
54
+ Requires-Dist: fastapi>=0.110; extra == "studio"
55
+ Requires-Dist: uvicorn>=0.27; extra == "studio"
56
+ Requires-Dist: ruamel.yaml>=0.18; extra == "studio"
57
+ Requires-Dist: python-multipart>=0.0.9; extra == "studio"
58
+ Provides-Extra: dev
59
+ Requires-Dist: build>=1.0; extra == "dev"
60
+ Requires-Dist: twine>=5.0; extra == "dev"
61
+ Requires-Dist: pytest>=7.0; extra == "dev"
62
+ Requires-Dist: httpx2>=0.1; extra == "dev"
63
+ Dynamic: license-file
64
+
65
+ <h1 align="center">BookForge</h1>
66
+
67
+ <p align="center">
68
+ <em>A book.yaml file and a folder of markdown in — a KDP-ready paperback, EPUB, and covers out.</em>
69
+ </p>
70
+
71
+ <p align="center">
72
+ <a href="https://pypi.org/project/bookforge-kdp/"><img alt="PyPI" src="https://img.shields.io/badge/pip%20install-book--forge-3b5bdb"></a>
73
+ <img alt="Python" src="https://img.shields.io/badge/python-3.10%2B-3b5bdb">
74
+ <img alt="Engine" src="https://img.shields.io/badge/engine-pandoc%20%2B%20weasyprint-1971c2">
75
+ <img alt="QA" src="https://img.shields.io/badge/verify-6%20automated%20checks-2f9e44">
76
+ <a href="https://github.com/pushkar-mishra/BookForge/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/pushkar-mishra/BookForge/actions/workflows/ci.yml/badge.svg"></a>
77
+ <img alt="Tests" src="https://img.shields.io/badge/tests-141%20passing-2f9e44">
78
+ <img alt="Self-built" src="https://img.shields.io/badge/self--built%20guide-130pp%20%C2%B7%200%20epubcheck%20errors-2f9e44">
79
+ <img alt="API keys" src="https://img.shields.io/badge/API%20keys-none%20required-2f9e44">
80
+ <img alt="Platforms" src="https://img.shields.io/badge/platforms-macOS%20%C2%B7%20Linux%20%C2%B7%20Windows-868e96">
81
+ <a href="https://github.com/pushkar-mishra/BookForge/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-868e96"></a>
82
+ </p>
83
+
84
+ <a href="https://raw.githubusercontent.com/pushkar-mishra/BookForge/main/docs/images/cover-front.jpg"><img src="https://raw.githubusercontent.com/pushkar-mishra/BookForge/main/docs/images/cover-front.jpg" alt="BookForge — The Step-by-Step Guide to Publishing Your Book on Amazon KDP, by Pushkar Mishra" height="360px" align="right"></a>
85
+
86
+ BookForge is the shared build pipeline left over after six independent
87
+ nonfiction book projects each hand-rolled their own scripts to solve the
88
+ same problem. Point it at a `book.yaml` file and a `content/` folder of
89
+ markdown chapters and it produces the same four deliverables every KDP
90
+ paperback + Kindle listing needs — with **no per-book fork of any build
91
+ script**.
92
+
93
+ **Repo:** https://github.com/pushkar-mishra/BookForge &nbsp;·&nbsp;
94
+ **License:** MIT &nbsp;·&nbsp; **PyPI:** `pip install bookforge-kdp`
95
+
96
+ > **This repo is the pipeline. `examples/sample-book/` is the manual.**
97
+ > It's a complete, real 130-page book — *BookForge: The Step-by-Step
98
+ > Guide to Publishing Your Book on Amazon KDP* — built entirely by the
99
+ > tool it documents, from nothing but its own `book.yaml` and markdown.
100
+ > See [The Book](#the-book) below.
101
+
102
+ <br clear="right"/>
103
+
104
+ ---
105
+
106
+ ## What you get
107
+
108
+ - **A 6x9in interior PDF** — mirrored margins, running page numbers, a
109
+ generated table of contents, half-title/title/copyright/About-the-Author
110
+ pages auto-generated from `book.yaml`
111
+ - **A validated EPUB3** — same source content, no embedded cover (KDP
112
+ supplies its own), passes `epubcheck` as part of the build, not after
113
+ - **A paperback wrap cover** — back + spine + front in one bleed PDF, spine
114
+ width computed automatically from the interior's actual page count
115
+ - **A Kindle front cover** — a separate JPG at the exact 1800×2700px KDP
116
+ expects
117
+ - **A ready-to-upload `amazon-kdp/` folder** — the four files above plus a
118
+ generated README, checklist, and listing metadata, all rendered straight
119
+ from `book.yaml` so nothing in it can drift out of sync
120
+
121
+ Everything runs **fully local** — no LLM calls, no API keys, no network
122
+ dependency once `pandoc` and `epubcheck` are installed.
123
+
124
+ ---
125
+
126
+ ## Two ways to use it
127
+
128
+ Both are fully supported, both read and write the same `book.yaml` and
129
+ `content/*.md`, and you can switch between them at any point — write a chapter
130
+ in the UI, build it from the terminal, or the reverse.
131
+
132
+ <table>
133
+ <tr>
134
+ <th align="left">Command line</th>
135
+ <th align="left">BookForge Studio (UI)</th>
136
+ </tr>
137
+ <tr valign="top">
138
+ <td>
139
+
140
+ ```bash
141
+ pip install bookforge-kdp
142
+
143
+ bookforge new ~/Books/my-book
144
+ cd ~/Books/my-book
145
+ ./build.sh
146
+ ```
147
+
148
+ Scriptable, CI-friendly, no web stack.
149
+
150
+ </td>
151
+ <td>
152
+
153
+ ```bash
154
+ pip install "bookforge-kdp[studio]"
155
+
156
+ bookforge studio
157
+ # → http://127.0.0.1:8000
158
+ ```
159
+
160
+ Write, press **Build book**, see the covers.
161
+
162
+ </td>
163
+ </tr>
164
+ </table>
165
+
166
+ Prerequisites are the same for both: **Python 3.10+**, plus `pandoc` and
167
+ `epubcheck` on `PATH` (`brew install pandoc epubcheck`, or `apt install pandoc
168
+ epubcheck`). `bookforge` checks for both at build time and prints an install
169
+ hint if either is missing.
170
+
171
+ ---
172
+
173
+ ## Quickstart — command line
174
+
175
+ ```bash
176
+ python3 -m venv .venv
177
+ .venv/bin/pip install bookforge-kdp
178
+ source .venv/bin/activate # puts `bookforge` on PATH for this shell
179
+ ```
180
+
181
+ > Skipped `source .venv/bin/activate`? Every command below still works if
182
+ > you spell out the full path instead, e.g. `.venv/bin/bookforge new ...`.
183
+
184
+ ```bash
185
+ bookforge new ~/Books/my-new-book --title "My Book" --author "Author Name"
186
+ cd ~/Books/my-new-book
187
+ # edit book.yaml and content/, then either:
188
+ ./build.sh # or build.bat on Windows -- runs the full pipeline
189
+ # ...or run each stage yourself:
190
+ bookforge build all # dist/interior.pdf + dist/{slug}.epub
191
+ bookforge covers # dist/cover-paperback.pdf + dist/cover-kindle.jpg
192
+ bookforge verify # QA checks — page count, spine math, epubcheck, ...
193
+ bookforge package # assembles amazon-kdp/ for upload
194
+ ```
195
+
196
+ While drafting, run `bookforge watch` (or `./build.sh watch`) in its own
197
+ terminal: it rebuilds on every save to `book.yaml`, `content/`, or
198
+ `assets/`, and a bad edit prints a clean error without killing the loop.
199
+
200
+ ---
201
+
202
+ ## Quickstart — BookForge Studio
203
+
204
+ Prefer a window to a terminal? Studio is a small local app that does the same
205
+ work: create chapters, write them, press **Build book**. It writes the same
206
+ files the commands do, so you can switch between the two freely.
207
+
208
+ ```bash
209
+ pip install "bookforge-kdp[studio]"
210
+ bookforge studio # or: bookforge studio path/to/book
211
+ ```
212
+
213
+ Then open <http://127.0.0.1:8000>. No account, no sign-in, nothing leaves
214
+ your machine — it binds to `127.0.0.1` only.
215
+
216
+ The UI is an **optional extra**: a plain `pip install bookforge-kdp` stays a CLI
217
+ with no web stack, and `bookforge studio` then tells you exactly what to
218
+ install rather than failing obscurely.
219
+
220
+ - **Landing screen** — start a new book, or open one. **Browse…** opens the
221
+ system's native folder dialog (the server opens it, since a browser can't
222
+ hand a page a real path), and books you've opened before are listed.
223
+ - **Chapters** — the sidebar *is* your table of contents. Adding a chapter
224
+ writes the markdown file **and** registers it in `book.yaml`; removing one
225
+ unlists it and leaves your words on disk.
226
+ - **Book details** — title, author, subtitle, biography, tagline, ISBN, plus
227
+ author-photo and cover-art upload, as a plain form. You never see YAML,
228
+ and `book.yaml` is edited in place with your comments intact.
229
+ - **Build book** — the full pipeline, with the six `verify` checks reported
230
+ in plain language ("Cover fits the interior").
231
+
232
+ Studio ships inside the package but behind the extra, so the two can never
233
+ disagree about internal APIs it uses (`book_outline()`, `verify_build()`).
234
+ See [`docs/STUDIO.md`](https://github.com/pushkar-mishra/BookForge/blob/main/docs/STUDIO.md), or Appendix D of the book.
235
+
236
+ ---
237
+
238
+ ## The book
239
+
240
+ *BookForge: The Step-by-Step Guide to Publishing Your Book on Amazon
241
+ KDP* — a complete 130-page manual, written and built entirely by
242
+ BookForge itself, source in
243
+ [`examples/sample-book/`](https://github.com/pushkar-mishra/BookForge/tree/main/examples/sample-book):
244
+
245
+ <a href="https://raw.githubusercontent.com/pushkar-mishra/BookForge/main/docs/images/cover-full.png"><img src="https://raw.githubusercontent.com/pushkar-mishra/BookForge/main/docs/images/cover-full.png" alt="BookForge — full wraparound cover (back, spine, front)" width="100%"></a>
246
+
247
+ | Part | Chapters |
248
+ |---|---|
249
+ | I. Before You Write | Why a Book Needs a Build Pipeline · Installing BookForge · Your First Project · The Config File |
250
+ | II. Writing Your Content | Where Content Goes · Parts, Chapters, and Numbering · Callouts and Diagrams |
251
+ | III. Building the Three Deliverables | The Interior PDF · The EPUB · The Covers |
252
+ | IV. Shipping to KDP | Verify · Package · Publishing to KDP · After You Publish |
253
+ | Appendices | The book.yaml Reference · Troubleshooting · Command Reference · BookForge Studio · Glossary |
254
+
255
+ Build it yourself:
256
+
257
+ ```bash
258
+ git clone https://github.com/pushkar-mishra/BookForge
259
+ cd BookForge && python3 -m venv .venv && .venv/bin/pip install -e .
260
+ source .venv/bin/activate
261
+ cd examples/sample-book
262
+ python3 assets/diagrams/gen_diagrams.py # generate the seven figures
263
+ ./build.sh # interior, EPUB, covers, verify, package
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Pipeline stages
269
+
270
+ | Command | Produces | Notes |
271
+ |---|---|---|
272
+ | `bookforge new` | a scaffolded project | `book.yaml` + starter `content/` + `assets/` + `build.sh`/`build.bat` |
273
+ | `bookforge build pdf\|epub\|all` | `dist/interior.pdf`, `dist/{slug}.epub` | EPUB fails the build on any `epubcheck` error |
274
+ | `bookforge covers` | `dist/cover-paperback.pdf`, `dist/cover-kindle.jpg` | spine width derived from the interior's page count |
275
+ | `bookforge diagrams render <dir>` | `*.png` next to each `*.svg` | rasterizes `bookforge.diagrams` DSL output for EPUB |
276
+ | `bookforge verify` | a pass/fail QA report | see [Verify](#verify) below |
277
+ | `bookforge package` | `amazon-kdp/` | copies build outputs + renders README/checklist/metadata |
278
+ | `bookforge watch` | continuous rebuilds | polls `book.yaml`, `content/`, `assets/` for changes |
279
+ | `bookforge studio` | the local web UI | optional extra: `pip install "bookforge-kdp[studio]"` |
280
+
281
+ Every new book also gets `build.sh` / `build.bat`, a thin wrapper around
282
+ the same commands: `./build.sh` (no args) runs `diagrams → build all →
283
+ covers → verify → package` in order and **stops at the first failure**
284
+ (e.g. a failing `verify` blocks `package` from ever running), or run one
285
+ stage at a time with `./build.sh pdf|epub|covers|diagrams|verify|package|watch`.
286
+
287
+ Every command re-reads `book.yaml` and re-globs `content/` on each
288
+ invocation — edit config or markdown, rerun (or leave `watch` running),
289
+ and the output always reflects current source.
290
+
291
+ ---
292
+
293
+ ## Verify
294
+
295
+ `bookforge verify` runs six checks against the current build, each one a
296
+ real KDP rejection reason turned into an automated gate instead of a
297
+ manual pre-upload ritual:
298
+
299
+ | Check | Fails when |
300
+ |---|---|
301
+ | `page_count_minimum` | interior is under KDP's paperback minimum (`kdp.min_pages`, default 24) |
302
+ | `spine_math_matches_cover` | the cover PDF's width doesn't match the spine width for the current page count |
303
+ | `epubcheck_zero_errors` | `epubcheck` reports any error on the built EPUB |
304
+ | `kindle_pixel_dims` | the Kindle cover isn't exactly 1800×2700px |
305
+ | `no_placeholder_text` | any chapter still contains draft markers |
306
+ | `chapter_frontmatter_complete` | a chapter referenced in `book.yaml` is missing or has no `title:` |
307
+
308
+ `verify` exits non-zero if any check fails, so it's safe to wire into CI.
309
+ Every failure also prints a `Recommendation:` line with the concrete next
310
+ step, not just the diagnosis:
311
+
312
+ ```
313
+ [FAIL] page_count_minimum: 10 pages (minimum 24)
314
+ ...
315
+ Recommendation:
316
+ - page_count_minimum: add 14 more page(s) of content (new chapters, or
317
+ longer existing ones) and rebuild, or lower kdp.min_pages in book.yaml
318
+ if this isn't going to KDP paperback
319
+ ```
320
+
321
+ ---
322
+
323
+ ## Repository layout
324
+
325
+ ```
326
+ src/bookforge/
327
+ config.py book.yaml schema — structure (parts -> chapters), metadata, palette, trim
328
+ assemble.py content/*.md + book.yaml -> one pandoc-ready markdown string
329
+ pdf.py assemble -> pandoc html5 -> WeasyPrint -> pypdf page count
330
+ epub.py assemble -> pandoc epub3 -> epubcheck
331
+ covers.py paperback wrap + Kindle cover, same WeasyPrint toolchain as pdf.py
332
+ callouts.py the 8 callout kinds (label + accent color + tint), shared by PDF and EPUB
333
+ diagrams.py SVG diagram primitives + a declarative DSL (flow / vflow / cycle)
334
+ raster.py PDF -> PNG/JPG via pypdfium2 (no system binary, all platforms)
335
+ verify.py the six QA checks above
336
+ package.py assembles amazon-kdp/ from dist/ + renders README/checklist/metadata
337
+ watch.py mtime-polling edit -> rebuild loop, no watchdog dependency
338
+ deps.py checks pandoc/epubcheck are on PATH, prints an install hint if not
339
+ errors.py BookForgeError hierarchy — user-causable failures print cleanly
340
+ cli.py argparse entry point wiring all of the above to `bookforge <command>`
341
+ templates/ interior.css, epub.css
342
+ scaffold/ the project `bookforge new` copies (including build.sh / build.bat)
343
+ tests/ 141 tests, no system binaries required
344
+ studio/ the optional local UI (FastAPI + vanilla JS), shipped
345
+ behind the `studio` extra so a plain install stays a CLI
346
+ ```
347
+
348
+ ### Book project layout
349
+
350
+ ```
351
+ mybook/
352
+ book.yaml # title, author, palette, trim size, table of contents
353
+ build.sh, build.bat # run the whole pipeline, or one stage at a time
354
+ content/
355
+ front/ # dedication.md, preface.md -- listed in book.yaml front_matter
356
+ chapters/ # ch01-slug.md, ... -- referenced from parts[].chapters
357
+ back/ # glossary.md, appendices -- listed in book.yaml back_matter
358
+ assets/
359
+ author/author-photo.png
360
+ cover/cover-art.png # optional; an auto-generated mark is used if absent
361
+ diagrams/ # *.svg sources (bookforge.diagrams DSL) + generated *.png
362
+ dist/ # gitignored -- build output
363
+ amazon-kdp/ # gitignored -- `bookforge package` output
364
+ ```
365
+
366
+ Half-title, title page, copyright page, table of contents, and the "About
367
+ the Author" page are always auto-generated from `book.yaml`. Everything
368
+ else is an ordinary markdown file listed in `front_matter`/`back_matter`,
369
+ or a chapter referenced from a `parts[].chapters` list.
370
+
371
+ ---
372
+
373
+ ## Front matter and the copyright page
374
+
375
+ Title, copyright, contents, and About-the-Author pages are generated from
376
+ `book.yaml` — but the wording and the page conventions are yours:
377
+
378
+ ```yaml
379
+ copyright:
380
+ notice: "{title} (c) {year} {rights_holder}."
381
+ rights: "Licensed under CC BY-SA 4.0, with attribution."
382
+ extra: ["Printed in the United Kingdom."]
383
+ # or, for a publisher who sets their own:
384
+ blank: true
385
+
386
+ pages:
387
+ half_title: false # drops the opening leaf, so copyright lands on p2
388
+ chapters_start_on: recto # every chapter opens on a right-hand page
389
+ ```
390
+
391
+ Emptying a paragraph omits it, so a Creative Commons book need not print
392
+ "All rights reserved". `blank: true` leaves the page present but empty — the
393
+ leaf still prints, so no page numbers shift. `recto` starts insert blank
394
+ versos where needed, and those carry no folio.
395
+
396
+ All of it is editable from Studio's **Book details**, with a live preview of
397
+ the finished copyright page.
398
+
399
+ ## Callout boxes
400
+
401
+ ```markdown
402
+ ::: takeaways
403
+ - First key takeaway
404
+ :::
405
+ ```
406
+
407
+ Pandoc's native fenced-div syntax — nothing BookForge invented. Available
408
+ kinds: `example`, `best`, `warning`, `tip`, `takeaways`, `note`,
409
+ `exercise`, `resources` — rendered consistently in both the PDF and the
410
+ EPUB from a single source of truth (`bookforge/callouts.py`).
411
+
412
+ Labels are per-book. Add a `callouts:` block to `book.yaml` to rename any
413
+ of them:
414
+
415
+ ```yaml
416
+ callouts:
417
+ warning: "WATCH OUT"
418
+ exercise: "TRY IT YOURSELF"
419
+ ```
420
+
421
+ ## Diagrams
422
+
423
+ ```markdown
424
+ {{DIAGRAM: my-diagram | A Diagram Title | What the diagram shows}}
425
+ ```
426
+
427
+ resolves to `assets/diagrams/my-diagram.svg` (PDF) or the rasterized
428
+ `.png` (EPUB), degrading to an italic "diagram pending" note if the asset
429
+ doesn't exist yet. Placeholders inside code fences are left verbatim, so a
430
+ book can document the syntax. Generate diagrams with the
431
+ `bookforge.diagrams` DSL (`flow`, `vflow`, `cycle`) — see
432
+ `examples/sample-book/assets/diagrams/gen_diagrams.py`.
433
+
434
+ ---
435
+
436
+ ## Engine
437
+
438
+ [pandoc](https://pandoc.org) (markdown → HTML5 / EPUB3) +
439
+ [WeasyPrint](https://weasyprint.org) (HTML/CSS → PDF), both called for
440
+ every book from the same shared `bookforge` package — one templating
441
+ language for the whole pipeline, no separate raster-graphics step for
442
+ covers. PDF→image conversion uses
443
+ [pypdfium2](https://github.com/pypdfium2-team/pypdfium2), which ships
444
+ prebuilt wheels for macOS, Linux, and Windows.
445
+
446
+ ## Full command reference
447
+
448
+ ```
449
+ bookforge new <path> [--title T] [--author A]
450
+ bookforge build pdf|epub|all [--config book.yaml] [--no-epubcheck]
451
+ bookforge covers [--config book.yaml] [--pages N]
452
+ bookforge diagrams render <dir>
453
+ bookforge package [--config book.yaml]
454
+ bookforge verify [--config book.yaml]
455
+ bookforge watch [--target pdf] [--config book.yaml]
456
+ bookforge studio [path] [--port 8000] # needs bookforge-kdp[studio]
457
+ bookforge --version
458
+ ```
459
+
460
+ ---
461
+
462
+ ## Developing BookForge itself
463
+
464
+ ```bash
465
+ git clone https://github.com/pushkar-mishra/BookForge
466
+ cd BookForge
467
+ python3 -m venv .venv
468
+ .venv/bin/pip install -e ".[studio,dev]"
469
+ .venv/bin/python -m pytest # 141 tests, ~1.3s, no system binaries needed
470
+ ```
471
+
472
+ Editable mode means changes to `src/bookforge/**` take effect immediately
473
+ — no rebuild step, just rerun `bookforge ...`.
474
+
475
+ To build a distributable package:
476
+
477
+ ```bash
478
+ .venv/bin/python -m build # writes dist/bookforge_kdp-*.whl and *.tar.gz
479
+ .venv/bin/twine check dist/*
480
+ ```
481
+
482
+ The version is declared once, in `src/bookforge/__init__.py`, and read
483
+ from there by `pyproject.toml`.
484
+
485
+ `templates/*.css` and `scaffold/**/*` are declared as package data, so
486
+ they're included automatically in both the editable install and the built
487
+ wheel. (One exception worth knowing: dotfiles like `scaffold/.gitignore`
488
+ don't survive glob-based package-data patterns and have to be listed
489
+ explicitly — see
490
+ [`PUBLISHING.md`](https://github.com/pushkar-mishra/BookForge/blob/main/PUBLISHING.md)
491
+ for why.)
492
+
493
+ **Publishing a release to PyPI** (as `bookforge-kdp` — `bookforge` was
494
+ already taken): the full runbook is in
495
+ [`PUBLISHING.md`](https://github.com/pushkar-mishra/BookForge/blob/main/PUBLISHING.md).
496
+
497
+ ---
498
+
499
+ ## Get to know the author
500
+
501
+ <img src="https://raw.githubusercontent.com/pushkar-mishra/BookForge/main/examples/sample-book/assets/author/author-photo.png" alt="Pushkar Mishra" width="120" align="left" style="margin-right: 16px;"/>
502
+
503
+ **Pushkar Mishra** is a technology leader with 20+ years across
504
+ engineering, architecture, and product leadership. He built BookForge to
505
+ stop hand-rolling a new build system for every book, then wrote *the
506
+ book on BookForge* using nothing but BookForge itself — proof, not just
507
+ documentation.
508
+
509
+ <br clear="left"/>