TECHNICAL CASE STUDY / BUILD YOUR HOME
How I used LLMs to turn 219 construction notes into 14 localized books.
Language models helped draft and localize a 227-page book. Stable source IDs, hashes, checkpoints, and validation kept the work traceable and recoverable.
01 / RESULT AND CONSTRAINT
219 notes became one source book and fourteen localized editions.
The delivered system produced a 227-page Croatian book with 88 illustrations, then generated fourteen localized books and storefronts. Every source note had a recorded destination when the source edition was released.
The input was a client’s collection of construction notes: explanations, decisions, warnings, comparisons, personal stories, tables, image requests, prices, and local procedures. LLMs helped turn this material into prose and later into other languages.
The notes did not stop changing when the first book was finished. The client could send a correction, a new lesson from the building site, or a replacement recommendation as another note. That note had to enter the same system, update the relevant part of the Croatian book, and then flow into every affected localization. The notes therefore remained the source of truth; the manuscript and PDFs were derived outputs.
The main constraint was completeness. A model could produce a convincing chapter while silently dropping a requested comparison, safety qualification, or illustration. Reading the prose was insufficient because fluency gives no indication that an input was omitted.
Every note needed a recorded destination. A new or edited note had to invalidate the affected output without forcing a complete rebuild.
The source notes and content cards remain authoritative before and after publication.The solution was to treat publishing as a build: structure the source, generate prose from controlled units, validate the result, and version every released artifact.
02 / NOTE-TO-CHAPTER TRACE
Each request received an identity before drafting began.
Each source note received a stable ID such as N-0219. I converted it into a content card that recorded the author’s intent, the outputs it requested, its destination chapter, claims that needed verification, and the state of any requested visual.
Related cards became a chapter brief before a model drafted or revised prose. One note could request several outputs in different chapters, so each requested output was tracked separately. The simplified example below shows why that distinction matters.
Compare three wall systems. Explain when each is used, show cost, speed, thermal performance, and trade-offs in a table, record why I chose one, and add a labelled wall section.
Definitions → evaluation criteria → comparison table → author’s decision → diagram
All four deliverable IDs remain attached when the prose is drafted.03 / LLM, CODE, AND HUMAN ROLES
The LLM was one component of the system.
The brief controls reading order while the deliverable IDs preserve the link to the note. In the example above, the explanation can move before the comparison and the author’s decision can move after it. If the illustration is missing, the audit still reports N-0XX / D4 as incomplete.
Drafted and revised prose, translated content units, and performed a separate target-language copy-edit.
Tracked IDs and hashes, validated returned units, saved checkpoints, rendered PDFs, and built release manifests.
Set the structure, checked claims and sources, judged voice and usefulness, reviewed pages, and approved releases.
This division matters because the three kinds of work fail differently. An LLM can omit or alter content. Code can enforce structure but cannot judge whether a story belongs in the book. A human can judge the result but should not have to compare fourteen books with 219 notes by hand.
By source version 0.10.75, every note had a destination and the Croatian edition was locked for release. “Locked” describes that build, not the end of the source. When a note changes later, its hash changes; the system marks the dependent card, chapter, and localized units as stale while reusing everything whose hash still matches.
04 / FAILURE RECOVERY
Every batch had to be safe to reject and rerun.
Long runs timed out or returned malformed JSON. Some responses omitted a key, changed an ID, reformatted a table, or returned 19 units after receiving 20. Good prose inside a response was irrelevant if the batch was incomplete.
Each unit carried an ID and a SHA-256 hash of its exact source, both of which the model had to return. The runner followed the same sequence for every batch:
01 / SELECTLoad only units whose current source hash has no verified output.
02 / REQUESTSend the units with a strict response schema and protected values.
03 / VALIDATECheck the complete ID set, hashes, numbers, protected strings, Markdown shape, and omit rules.
04 / COMMITWrite the verified batch to a temporary file and rename it atomically.
05 / RECOVERReturn the exact validation error, retry, and split a repeatedly failing batch into smaller halves.
A session cost ceiling stopped unattended work. After a timeout or manual stop, the next run skipped every verified unit and resumed at the first missing or stale hash.
Accepted output is cached by source hash; rejected output never enters the build.
05 / LOCALIZATION AS A BUILD
The localization rules had to cover local advice.
The source contained Balkan prices, procedures, public services, and examples. A literal translation could present them as advice for a German, French, or British reader. The international edition profile removed these local units and retained the construction principles that applied across markets. Readers are directed to local authorities or professionals for current regulations.
I benchmarked three models on narrative prose, technical terminology, safety language, tables, and a passage that should be omitted. The production model—openai/gpt-6-luna through OpenRouter—was pinned in configuration after it produced the best terminology and least literal German and French in that test. A runtime flag cannot silently swap it.
INPUT UNITID, source hash, scope, Markdown, protected tokens, numeric and date signatures
MODEL OUTPUTThe same ID and hash, an explicit translated-or-omit status, target text, and notes
VALIDATIONComplete return set, unchanged protected values, matching structure, locale number rules, no Croatian residue
STATERequested and served model, provider, latency, token usage, API cost, and atomic checkpoints
Translation and copy-editing run as separate stages. Translation preserves structure and meaning. Copy-editing adjusts rhythm and target-language terminology while validation protects claims, measurements, warnings, citations, and URLs.
The production state files recorded the following localization costs. These figures cover model calls for the books; they exclude software development, editorial work, image production, PDF review, storefront work, and the earlier model benchmark.
The second copy-edit found incorrect English decimal punctuation, awkward German constructions, French number grouping, and one shift in meaning from “expert” to “artisan.” Low API cost made the extra pass affordable; native-language judgment was still required to decide what needed correction.
06 / VERSIONS, STRIPE, AND TESTS
A new note starts a controlled chain of new versions.
The first wave produced fourteen localized books and storefronts at buildyourho.me. Later notes use the same route as the original 219. A changed note creates a new hash, the affected Croatian content is rebuilt and reviewed, and a new source version becomes the input to localization.
An edition ID makes both parts visible. In en-GB-0.10.75.2, en-GB is the locale, 0.10.75 is the Croatian source version, and 2 is that locale’s second revision. A German copy-edit can therefore create a new German revision without pretending that the Croatian source changed.
Every release manifest records the edition ID, source version, localization revision, checksum, file path, filename, and page count. Full PDFs, samples, localized product copy, and storefront data are generated from that state.
How payment and download access fit into the chain
CHECKOUTThe server resolves the active release for the selected language and puts its locale, edition ID, and SHA-256 checksum into Stripe Checkout metadata.
PAYMENTA signed Stripe webhook creates access only for a completed, paid session. Unpaid events and invalid signatures are rejected.
ACCESSThe buyer receives a short-lived signed download token for the language they purchased.
DOWNLOADThe order keeps the purchase-time edition metadata for audit, while the download serves the current active PDF for that language.
REFUNDA partial refund keeps access; a full refund revokes it. A later out-of-order paid event cannot restore a fully refunded order.
Serving the latest active language edition is a product decision. The system preserves what was sold in the order record, but production does not promise that every later download returns the old binary. Historical releases can remain in the editorial archive without keeping every revision in the download service.
The release gate is backed by automated tests
Tests reject missing IDs, stale source hashes, changed numbers or protected strings, broken Markdown structure, incorrect locale punctuation, and content that should have been omitted.
Verification checks PDF and sample page counts, checksums, required files, and illustration coverage. Rendered pages are still inspected for layout failures.
Tests cover unpaid sessions, valid and invalid webhook signatures, paid downloads in every locale, purchase metadata, partial refunds, full refunds, and late Stripe events.
The code catches missing units and invalid state. Reviewing rendered pages catches different failures: an isolated heading, a clipped illustration, or a comparison table that no longer fits after German text expands.
Notes are authoritative. Source releases freeze reviewed input. Locales derive from that source. Stripe records what was active at purchase.
07 / REUSABLE PATTERN
The same design works when one source feeds many documents.
The book is one instance of a broader pattern. Policies feed regional handbooks, product data feeds catalogues, research feeds reports, and course material feeds several formats or languages. In each case, a source change can invalidate several downstream artifacts.
- Give source units stable identities. Split the input at boundaries that can be reviewed, transformed, and invalidated independently.
- Record intent before generating prose. Store requested outputs, scope, destination, protected values, and verification needs.
- Define what the model may change. Separate free prose decisions from invariants such as IDs, numbers, citations, structure, and omit rules.
- Validate before caching. Reject an entire unit or batch when the response is incomplete; save only output tied to the current source hash.
- Separate history from delivery policy. Give each release a version, checksum, and manifest entry, then decide explicitly whether customers receive the purchased binary or the newest compatible revision.
This structure is useful when the source changes, several outputs depend on it, omissions are expensive, or users need historical versions. A one-off, low-stakes document usually does not need it.
I would make three changes if starting again: define the unit schema and release manifest before drafting, involve native readers before the first localized release, and turn the first observed failure into a regression test. Adding these controls later required migration and repeated review.
Use LLMs for language variation. Use code for state and invariants. Use people for judgment.