bookforge makes a failed PDF physically unable to reach final/
주제 한 줄 → 상업도서급 한국어 전자책 PDF. Claude Code·Codex 겸용 에이전트 스킬 — 6 스타일 팩, 실측 기반 배치 규칙서, 밀도 QC 게이트
At a glance
- What is it?
- bookforge is an agent skill that turns one line of topic, or a draft manuscript, into a typeset Korean ebook PDF across six measured style packs. Its unusual design is that quality control is not advisory: a gate failure removes the artifact, and a mutation suite tests whether the gates detect anything at all.
- Who is it for?
- bookforge suits a writer who works in markdown and wants a real book structure rather than a document export, since the output includes covers, leader-dot contents pages, running heads, and a colophon, and since the two engines cover both technical reports and trade paperbacks. It does not suit a quick one-page handout, and it does not suit an offline machine without Typst 0.14, Python 3, and a global Chromium, because the skill checks its own prerequisites before it starts.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 30 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A PDF that fails the gate cannot exist in final/
The content side of bookforge is markdown, nothing more. Everything a reader sees as a book, from the cover and the leader-dot contents pages through chapter overlines, running heads, and the colophon page, is produced by typesetting rather than by writing. Six style packs and a set of scripts own that job, and a quality gate owns the verdict.
The gate is enforced physically rather than advisory. A PDF that does not pass cannot exist in the `final/` directory. There is no flag to skip it and no warning to acknowledge, so a book reaches the output directory only by satisfying the checks.
What the gate inspects goes beyond the finished file. It validates the color and numeric contract of a style pack before rendering, under the identifier G16. It blocks the failure mode where a whole document quietly shrinks through the build, caught by a radical cross-check labeled G1-SCALE. And it rechecks, in the final imposition, whether a diagram splits across a page boundary or overflows the text area, which is G17. Content that passes all three still faces a density check that catches unmotivated emptiness and forced filling as numbers rather than as taste.
The mutation suite decides whether the gates catch anything at all
A gate that never fails proves nothing, so bookforge carries a mutation suite under `tests/mutations/` that deliberately breaks books on purpose. Each run asks two questions. Does a book with an injected defect get caught by the gate? And does a normal book escape without a false alarm?
The verdict is organized into 25 judgment axes, and the suite includes an unmutated control group, M0, so the no-defect baseline is measured on every run rather than assumed. That control is the part most test suites skip: without it, a gate that fails everything looks identical to a gate that works.
This design also explains why the gate identifiers appear throughout the documentation as a numbered vocabulary rather than as prose. G0 validates diagram sources before rendering, G2 hard-requires zero Type3 objects in the output, G13 confirms after rendering that label text actually exists in the PDF, G16 checks that the theme matches its own declaration, and G17 rechecks figure fit at imposition. Each of those numbers is a specific sensitivity pinned by a regression test, which is a stronger claim than a feature bullet claiming thoroughness.
AntV figures render through a bundle committed to the repository
Figures come in two tracks, and the first one avoids the network entirely. For order, comparison, hierarchy, and numeric trends, the agent declares a figure in `diagrams/fig-NN.json` using AntV Infographic DSL. The renderer does the server-side rendering with `vendor/antv-ssr.bundle.mjs`, a bundle committed into the repository, and `@antv/infographic` is pinned at exactly 0.2.19 rather than floating on a caret range.
Because the bundle is vendored, `npm ci` is unnecessary for building. Reproducibility survives the npm registry disappearing, which is the stated reason for committing it. The recovery path exists for the one failure the vendoring cannot prevent, a lost bundle, and it runs `npm ci && node vendor/build-bundle.mjs` from the skill folder.
Chromium is still required for this track, and it must be global. Installation is `npm i -g playwright && npx playwright install chromium`, and the build resolves playwright from the global npm root, so a project-local install does not satisfy it. The prerender harness goes through Chromium even for the four Typst styles, which means diagram work pulls in a browser that plain text typesetting does not need.
Eleven authored diagram families bypass AntV and get baked by the build
The second track covers what the AntV catalog does not: eleven families, named as sequence, state machine, ER, swimlane, Gantt, radar, venn, scatter, org chart, loop, and permission matrix. The agent draws these as SVG directly, placing `diagrams/fig-NN.svg` with a sidecar file carrying `kind` set to `authored`. The build then normalizes the file, applying font baking, palette enforcement, a label overlap check, and an eight point minimum, and writes the result to `assets/fig-NN.svg`.
Size is a contract rather than a preference. A diagram taller than `diagram.maxHeightMm` is either pre-scaled at the render stage or rejected, and the attempt is recorded in a figFitReport; the final PDF catches any circumvention through G17-FIGFIT, which cross-checks page splitting, page-area overflow, and recomputed height. Ink is a contract too. Every palette color declares a role among label, fill, and stroke, so using a label color as an area fill is a gate failure rather than a visual preference, and label ink cannot exceed the body contrast ceiling in `diagram.labelBand.maxRatio`. Sources are checked before rendering by G0 and the presence of label text in the PDF after rendering by G13. The authoring contract, type routing, connector rules, and complexity budget live in `references/diagrams.md`, which absorbs the specification of cathrynlavery/diagram-design under MIT and restates it for Korean typesetting, palette tokens, and the gate system.
Six contents grammars are declared, and a theme that drifts fails before the build
Each style has its own table-of-contents grammar, and the grammar is a declared contract rather than a visual preference. A layout catalog named `TOC_LAYOUTS` holds six layouts, each registered with its level count, whether it carries leader lines, and its ink ceiling as measured values. A style pack only chooses the name, through `toc_layout` in `tokens.json`, and if the theme's actual behavior disagrees with the declaration, G16-SYNC stops the build before it starts.
The six differ more than a reader would notice. `hanging-two-level` for insight uses a chapter row with an indented section row and switches to boxed pagination on overflow, marked `toc_overflow: paginate` with two-pass page-number markers. `spread-single-level` for magazine fixes the contents to one spread, keeps chapter level only, and aborts the build on overflow. `display-numeral` for business, and as a magazine alternative, uses a large left numeral column with titles on the right. `twocol-balanced` for practical combines a header band, ordinal chips, and dotted leaders, splitting into two balanced columns when it overflows. `academic-flow` for academic pairs a number column with a right-aligned page number, and `flush-single-level` for essay allows chapter level only and forbids leader lines entirely.
Alternatives can be enabled per book: declaring `toc_layout` in `book.json` typesets magazine as `display-numeral`, with the alternative's page capacity governed by a separate measured contract, `toc_capacity_alt`. Boxed contents styles can also publish a list of figures and tables on its own page through the `toc_lists` option, and the gate cross-checks those page numbers as well.
G14 cross-checks the contents in five directions against the printed book
A contents page that is merely plausible is the most common failure in book production, because nothing looks wrong until a reader turns to page 84. G14 exists for that class of problem and scans five axes.
Axis A compares printed contents page numbers against the actual folios. Axis B compares the contents against the chapter overline color family by hue, so a chapter whose overline changes tone still reads as one section. Axis C checks the background contrast of chromatic text against the WCAG lower bound, which is a legibility rule rather than a preference. Axis D compares section-row page numbers against the page on which each section actually starts, catching contents that are internally consistent but wrong. Axis E compares list of figures and tables page numbers against the page carrying the real caption, which is the check that only runs when `toc_lists` is on.
Together these are five independent ways a contents page can lie while looking fine, and all five are mechanical comparisons. That is the practical difference between a style pack that picks fonts and one that also has to survive being checked.
TrueType fonts ship in the repo because Chromium falls back to Type3
Five OFL fonts, Pretendard, Noto Serif KR, Paperlogy, Gmarket Sans, and Barlow, are bundled in the repository, all of them as TrueType, and they render immediately. The reason is a specific renderer behavior rather than a licensing convenience.
Chromium print-to-PDF cannot subset CFF outlines, which is what an OTF file carries, so it silently falls back to Type3 and redraws glyphs as vectors on every page. The measurement recorded in the documentation uses the same body text for both cases: the OTF version produced 19 Type3 objects, while the converted TTF version produced one Type0 subset and zero Type3 objects.
The gate treats that as a hard condition. G2 requires zero Type3 objects in the output, so a book that reintroduces a CFF font fails instead of shipping a file that renders correctly and weighs more than it should. License notices for the bundled fonts live at `assets/fonts/LICENSES.md`, which is why the fonts can be committed at all. The self-check the skill performs before running also covers the toolchain: Typst 0.14 or later for the four Typst styles, Python 3 with PyMuPDF and markdown-it-py for conversion and the gates, and the global Chromium for the two HTML styles and for every book that uses figures.
Installation is a clone followed by three symlinks, because both agent tools support skill directories as links.
git clone https://github.com/gongnyang/bookforge.git
cd bookforge
ln -sfn "$PWD" ~/.claude/skills/bookforge
ln -sfn "$PWD" ~/.codex/skills/bookforge
ln -sfn "$PWD" ~/.agents/skills/bookforgeLinking rather than copying keeps one checkout to update when the skill changes.
Six style packs span two engines, and a bad cover choice fails loudly
The six packs are measured rulebooks, each with its own `STYLE.md` holding trim size, font sizes, leading, color tokens, page templates, and prohibitions taken from real commercial publications. Two engines cover them. Typst handles practical, academic, essay, and business; HTML through Chromium handles insight and magazine. The trims are 153 by 225 for practical and academic, 128 by 188 for essay, 200 by 280 for business, 182 by 257 for insight, and 200 by 265 for magazine.
Typography choices are as specific as the trims. Practical sets its prose low in a serif, Noto Serif KR, and stands its operations, labels, and numbers in a gothic, Pretendard, so reading text and doing text are separated by typeface rather than by color. Academic follows the new Korean page conventions with a three-line running head and a numbered section hierarchy. Essay is minimal, A5 with one degree of black plus a single spot color. Business runs a navy system with action titles and key statistics. Magazine uses an editorial grid with full-bleed pages.
The practical cover is a catalog. The default is `numeral`, an oversized ghost number on a blank ground, and `cover_variant` in `book.json` can opt into `ribbon`, which was the earlier default, `block`, `grid`, or `obi`. A value outside the catalog fails immediately, with no silent fallback, which is the same philosophy as the gate that keeps a bad PDF out of `final/`.
Editorial conclusion
bookforge suits a writer who works in markdown and wants a real book structure rather than a document export, since the output includes covers, leader-dot contents pages, running heads, and a colophon, and since the two engines cover both technical reports and trade paperbacks. It does not suit a quick one-page handout, and it does not suit an offline machine without Typst 0.14, Python 3, and a global Chromium, because the skill checks its own prerequisites before it starts. Before your first build, read references/pagination.md for the layout rules and scripts/build.py for the actual pipeline, since those two files decide more about the result than the style name does.
Frequently asked questions
What does bookforge need installed before it can build a PDF?
Typst 0.14 or later for the practical, academic, essay, and business styles, Python 3 with PyMuPDF and markdown-it-py for conversion and the QC gates, and a global Playwright Chromium for insight, magazine, and any book using diagrams. The build resolves playwright from the global npm root, so a project-local install does not satisfy it.
Which typesetting engines does bookforge use for its six styles?
Typst handles practical, academic, essay, and business, while insight and magazine go through HTML to Chromium. Diagram prerendering passes through the Chromium harness even for the Typst styles.
How does bookforge stop a failing PDF from reaching the output directory?
The gate is physical: a PDF that does not pass cannot exist in `final/`. It validates the style pack contract before rendering under G16, blocks silent global shrinking under G1-SCALE, and rechecks diagram page splits and page-area overflow in the final imposition under G17.
What is the difference between the two bookforge diagram tracks?
The antv track declares figures in `diagrams/fig-NN.json` in AntV Infographic DSL and renders them through a vendored SSR bundle with text converted from foreignObject to native text. The authored track draws eleven families the catalog does not cover as `diagrams/fig-NN.svg` with a sidecar marked authored, and the build normalizes font baking, palette, label overlap, and an eight point minimum.
Can bookforge render diagrams without the npm registry?
Yes, because the renderer uses the bundle committed at `vendor/antv-ssr.bundle.mjs` and `npm ci` is unnecessary for building. Only if the bundle is lost do you recover it with `npm ci && node vendor/build-bundle.mjs` from the skill folder.
How is bookforge installed as an agent skill?
Clone the repository, change into it, and symlink the checkout into three locations: `~/.claude/skills/bookforge`, `~/.codex/skills/bookforge`, and `~/.agents/skills/bookforge`, using `ln -sfn "$PWD"` for each. Both Claude Code and Codex officially support skill symlinks.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gongnyang-bookforge)