The Bible as structured JSON, one file per chapter, with multiple parallel texts per verse. New Testament: Latin Vulgate, Greek Textus Receptus, Finnish Biblia 1776, and English King James. Old Testament: Latin Vulgate, Hebrew Masoretic (full pointing), Douay-Rheims, Finnish Biblia 1776, and English King James. Verse-by-verse alignment across traditions.
bible/<testament>/<CODE>/<NNN>.json
testament is nt (New Testament), ot (Old Testament), apo (Apocrypha), or lxx (Septuagint). CODE is the canonical uppercase three-character book code. NNN is the chapter, zero-padded to three digits so every book (including Psalms with 150 chapters) sorts consistently.
{
"verse": 1,
"latin_vulgate": "...",
"greek_textus_receptus": "...",
"finnish_biblia": "...",
"king_james": "..."
}
The three scraped columns (Latin, Greek, KJV) come from the interlinear source
site. Any further edition registered for nt in data/editions.json (currently
Biblia 1776) is overlaid at the scraped KJV verse positions by identity; a
missing overlay verse would be marked refs.<edition>.absent (Biblia 1776
covers all 7,957 NT verses, so none is currently marked).
{
"verse": 1,
"latin_vulgate": "...",
"hebrew_masoretic": "...",
"king_james": "...",
"refs": {
"hebrew_masoretic": { "src": "1:1" },
"latin_vulgate": { "absent": true }
}
}
- The OT
versefield uses KJV versification for all traditions. - The
refsfield is present only when a tradition diverges, and is keyed by edition id with a uniform per-edition object:refs.<edition>.src— the source"chapter:verse"when that edition's versification places the verse elsewhere than KJV numbering (e.g. Hebrew psalm titles, the Latin psalter).refs.<edition>.absent: true— the edition has no text at that position (the edition's column is empty). Ten KJV verses are absent in the Clementine Vulgate; no Hebrew verse is currently absent.- Both keys can appear together for one edition (relocated and empty). The base edition (KJV) never appears in
refs.
- Hebrew text includes full Masoretic pointing (vowels and cantillation marks), normalized to NFC form.
Each parallel text is registered in data/editions.json. A row is self-describing and drives generation by itself — the OT pipeline names no edition. A row carries:
id— the verse-column key (and header is taken fromdisplay_name_field).source—{ "type": ..., ... };typeselects a source backend (scrollmapper,sefaria) viatools/sources/registry.py.book_name_field— whichdata/books.jsonfield holds this source's per-book name.vmap_key— the versification namespace indata/versification/ot-versification.json(omitted for the base edition, which defines verse positions).base: true— the edition that defines verse positions (KJV). Non-base editions render first; the base renders last.
Adding a new parallel OT text needs only a registry row (plus the source's per-book name in data/books.json, and a cache/network fetch). The generator (tools/generate_ot.py), merge engine (tools/merge_ot.py), and validator (tools/validate_ot.py) iterate the registry and need no per-edition edits. Only a genuinely new source backend (a source.type not yet handled) requires one new class in tools/sources/registry.py.
The Apocrypha use the Authorized KJV-with-Apocrypha (Scrollmapper KJVA) as the
verse-position spine — 14 books, 5,717 verses, Greek/KJV-family versification, so
the English column stays KJV across the whole corpus. A second column carries the
Finnish Biblia 1776 (FinBiblia).
Cross-edition apocrypha alignment is identity placement with no versification
map: TVTMS treats KJVA and Biblia 1776 as the same tradition and provides no
verse map between them, so none is fabricated. Where Biblia 1776 has no text the
verse is marked refs.finnish_biblia.absent. Biblia 1776 ships empty placeholders
for I/II Esdras and a different Greek-Esther unit than KJV's "Additions to Esther",
so those three books are fully Finnish-absent; total Finnish-absent is 1,505 verses.
The Latin/Vulgate and Douay-Rheims Apocrypha belong to a different versification family (e.g. Sirach diverges in 48 of 51 chapters, and the Daniel/Esther additions are embedded rather than separate books) with no map in our sources — a future plan.
All underlying texts are in the public domain:
- King James Version (1611): Sourced from Scrollmapper's bible_databases datasets.
- Clementine Vulgate (Latin, 1592): Sourced from Scrollmapper's bible_databases datasets. Ten OT verses are merged into the preceding verse in the Vulgate tradition (recorded as
refs.latin_vulgate.absent). - Douay-Rheims (Challoner) (English, 19th c. revision): Sourced from Scrollmapper's
DRCdataset. Follows Vulgate versification, so it reuses the same KJV→Vulgate map as the Clementine Vulgate (vmap_key: "latin"); thirteen KJV verses are merged/absent in the Douay tradition. - Hebrew Masoretic Text (Westminster Leningrad Codex): Sourced via the Sefaria API. Includes full Masoretic pointing with vowels and cantillation marks.
- Biblia 1776 (Finnish, 1776): Sourced from Scrollmapper's
FinBibliadataset. Already KJV-versified for the protocanon and NT, so it is placed by identity with no versification map. - Greek Textus Receptus (NT only): Sourced from the Logos Apostolic interlinear (https://www.logosapostolic.org/bibles/latin_vulgate_textus_receptus_king_james/).
- Swete 1909 Greek Old Testament (Septuagint / LXX): H. B. Swete, The Old Testament in Greek (1909). Public Domain by age. Sourced as PD text, not from any GPL repackaging.
The morpho-lexical layer adds the following sources (see the Morpho-Lexical Floor section below):
- STEPBible TAGNT (Translators Amalgamated Greek NT), TAHOT (Translators Amalgamated Hebrew OT), and TBESG (Translators Brief Exhaustive Strong's Greek): CC BY 4.0, produced by STEPBible and Tyndale House Cambridge. Supply per-word lemma, morphology, Strong's numbers, and English glosses for the NT Greek and OT Hebrew. Credit STEPBible and link to https://github.com/STEPBible.
- MACULA Greek and Hebrew Linguistic Datasets (Clear Bible Inc.): CC BY 4.0. Supplies Louw-Nida section references (Greek) and SDBH LexDomain codes (Hebrew) for semantic domains. https://github.com/Clear-Bible/macula-greek and https://github.com/Clear-Bible/macula-hebrew.
- Strong's Exhaustive Concordance Greek and Hebrew dictionaries (James Strong, 1890): Public Domain. XML encoding by Ulrik Petersen / openscriptures. https://github.com/openscriptures/strongs. Rendering policy: English gloss text and transliterations normalize the tetragrammaton to "Yahweh" at build time (Strong's own "Jehovah" is a hybrid form never pronounced by any tradition); the cached source XML is untouched. The seven KJV verses that read "Jehovah" keep the KJV's own text, since that column reproduces the 1611 edition verbatim.
- openscriptures GreekResources LxxLemmas (Open Scriptures Septuagint Project, David Troidl): CC BY 4.0. Supplies per-word Greek lemmas and the lemma-to-Strong's join for the LXX corpus. https://github.com/openscriptures/GreekResources.
The OT cross-tradition verse alignment is derived from STEPBible's TVTMS (Translators Versification Traditions Mapping System), produced by Tyndale House Cambridge. This data is licensed CC BY 4.0. A small hand-authored CC0 supplement (data/versification/ot-versification-supplement.json) aligns the Decalogue chapters (Exodus 20, Deuteronomy 5) to the Sefaria verse division.
The LXX versification map (data/versification/lxx-versification.json) is derived from the same TVTMS file's Greek/LXX tradition column (CC BY 4.0). A companion CC0 supplement (data/versification/lxx-versification-supplement.json) covers chapter-level reorderings and integrated additions that TVTMS does not model at the verse level: Jeremiah chapter reorder, Greek Esther additions A-F, and Greek Daniel integrated books.
Credit STEPBible and link to https://github.com/STEPBible when using this compilation.
This project mixes three license regimes by artifact type. See
docs/LICENSING.md for the authoritative, per-artifact map.
- Software (everything under
tools/, build scripts, tests): AGPL-3.0-or-later — seeLICENSE. - Content, default: CC0-1.0 public-domain dedication
(
licenses/CC0-1.0.txt). Covers the original compilation/schema, the hand-authored CC0 versification supplements, the public-domain biblical text corpora (Westminster Leningrad Codex, Clementine Vulgate, King James Version, Swete 1909 Greek OT), and the Strong's dictionary spine. - Content derived from CC-BY sources: CC-BY-4.0
(
licenses/CC-BY-4.0.txt), attribution required:- STEPBible TVTMS versification, and TAGNT / TAHOT / TBESG / TAGOT morpho-lexical data — STEPBible.org, Tyndale House Cambridge, CC-BY 4.0.
- MACULA Greek/Hebrew semantic-domain data — Clear Bible Inc., CC-BY 4.0.
- openscriptures LxxLemmas Septuagint lemmas — David Troidl, CC-BY 4.0.
Where a single datum combines a public-domain value with a CC-BY tag, the CC-BY
attribution above applies. Every generated datum carries src/sources
provenance so its governing license is traceable.
Generate NT chapters from the Logos Apostolic interlinear:
python -m tools.generate
Validate structure and pin output against the independently produced james JSON:
python -m tools.validate
Generate the OT versification map from STEPBible data and Sefaria sources:
python -m tools.tvtms
Generate OT chapters:
python -m tools.generate_ot
Validate OT structure. This checks all 23,145 OT verses, contiguity, non-empty verse bodies (except marked-absent), and alignment against versification oracles:
python -m tools.validate_ot
Generate Apocrypha chapters:
python -m tools.generate_apo
Validate Apocrypha structure:
python -m tools.validate_apo
Raw sources are cached in data/cache/ (gitignored).
Generate the LXX corpus from the Swete 1909 PD text (requires Swete CSVs in data/cache/morph/raw/lxx/):
python -m tools.generate_lxx # -> bible/lxx/ (Swete PD)
Normalize LxxLemmas to the intermediate TSV (requires openscriptures JS files in data/cache/morph/raw/lxx/lxxlemmas/):
python -m tools.morph_norm.lxx # -> data/cache/morph/lxx.tsv (lemmas + Strong's join)
Generate CoNLL-U morphology files for the LXX (lemma + Strong's only; UPOS/XPOS/FEATS intentionally empty):
python -m tools.generate_morph --testament lxx # -> morph/lxx/
Validate LXX structure and morphology coverage:
python -m tools.validate_lxx
python -m tools.validate_morph lxx
Build lexicon (adds LXX-only lemma-keyed entries to lexicon/grc/):
python -m tools.build_lexicon # + LXX-only lemmas
Rebuild the derived MT<->LXX bridge and token database (both are gitignored):
python -m tools.align_mt_lxx # -> data/cache/mt-lxx-bridge.jsonl (derived aggregate)
python -m tools.build_db # -> data/tokens.sqlite (+ lxx tokens + mt_lxx table)
Raw source caches are in data/cache/morph/raw/lxx/ (gitignored). See the Septuagint Layer section for artifact details.
Normalize STEPBible morphological data to the intermediate TSV format (requires raw STEPBible files in data/cache/morph/raw/):
python -m tools.morph_norm.stepbible_greek # raw -> data/cache/morph/grc.tsv
python -m tools.morph_norm.stepbible_hebrew # raw -> data/cache/morph/hbo.tsv
Generate canonical CoNLL-U morphology files:
python -m tools.generate_morph # -> morph/**/*.conllu
Validate against the L0 corpus and pinned coverage oracles:
python -m tools.validate_morph nt && python -m tools.validate_morph ot
Build MACULA semantic domain maps (downloads once, cached in data/cache/):
python -m tools.fetch_macula # -> cached MACULA domain maps
Build lexicon entries from Strong's + TBESG + MACULA domains:
python -m tools.build_lexicon # -> lexicon/**/*.json
Build the derived SQLite token database:
python -m tools.build_db # -> data/tokens.sqlite
The morpho-lexical layer adds per-word lemma, morphology, Strong's numbers, lexicon entries, and semantic domains to the L0 verse corpus. It uses a two-form architecture: canonical hand-editable source files (version-controlled) and a derived projection (gitignored, rebuildable).
Canonical artifacts (version-controlled, human-editable):
morph/<testament>/<CODE>/NNN.conllu(L1) — CoNLL-U files; one file per chapter, one sentence per L0 verse, one token row per word. Each token carries FORM (from L0), LEMMA, XPOS (raw STEPBible morph code), FEATS (CoNLL-U features, reserved for future expansion), and MISC fields includingStrong=G####(Strong's number),Translit=...(transliteration), andAlign=matched|unmatched(alignment status). Mismatches between the L0 surface and the STEPBible text are markedAlign=unmatchedrather than silently dropped.lexicon/<lang>/<STRONG>.json(L2a) — one JSON entry per Strong's number present in the corpus (Greek underlexicon/grc/, Hebrew underlexicon/hbo/). Each entry carries:strong,lemma,translit,lang(ISO 639-3),pos,glosses(language-keyed map; currently English only),senses(one per gloss),domains(sorted atomic domain codes),root(Strong's ID of root word, or null), andsources(list of source labels that contributed data).
Derived projection (gitignored, rebuilt from canonical files):
data/tokens.sqlite— SQLite database built frommorph/+lexicon/+ L0 corpus. Holds no truth the canonical files lack; delete and rebuild at any time. Supports four query classes: concordance (all verses containing a given Strong's), thesaurus (Strong's numbers sharing a semantic domain), cross-translation (L0 verse text alongside lemma and gloss), and morphological queries (verses filtered by FEATS pattern).
Registry:
data/morph-sources.json— one entry per language; drives normalization, alignment, and lexicon building. Each row specifies the language code, testament, L0 field name, normalized TSV path, edition filter, and domain source label. Adding a new language requires only a new registry row; the generator and validator need no per-language edits.
| Dimension | NT (Greek) | OT (Hebrew) |
|---|---|---|
| Verses | 7,957 | 23,145 |
| Tokens | 140,610 | 312,079 |
| Unmatched tokens | 6,615 (4.70%) | 14,794 (4.74%) |
Unmatched tokens reflect genuine surface divergence between the L0 corpus (Textus Receptus / Westminster Leningrad Codex) and the STEPBible alignment text; they are not errors. Only unmatched tokens lack a Strong= field by design.
Lexicon: 13,548 entries total (5,122 Greek + 8,426 Hebrew).
| Dimension | Greek | Hebrew |
|---|---|---|
| Entries | 5,122 | 8,426 |
| English-gloss coverage | ~99% | ~99% |
| Semantic domain coverage | 99.2% (Louw-Nida) | 89.8% (SDBH) |
Greek semantic domains use Louw-Nida section references (e.g. "25.43") sourced from the MACULA Greek Nestle1904 TSV (ln column). Hebrew semantic domains use SDBH LexDomain hierarchical codes (e.g. "002003003004") sourced from MACULA Hebrew WLC node XML files. The ~10% of Hebrew strongs without SDBH codes are morphology-only entries (particles, prefixes, proper nouns) that MACULA does not classify.
- STEPBible TAGNT / TAHOT / TBESG: "Data created by www.STEPBible.org based on work at Tyndale House Cambridge (CC BY 4.0). Source: https://github.com/STEPBible"
- MACULA Greek / Hebrew: "MACULA Greek/Hebrew Linguistic Datasets, Clear Bible Inc., CC-BY 4.0. https://github.com/Clear-Bible/macula-greek and https://github.com/Clear-Bible/macula-hebrew"
- Strong's Greek / Hebrew dictionaries: Public Domain -- Strong's Exhaustive Concordance, James Strong 1890. XML by Ulrik Petersen / openscriptures.
The Septuagint (LXX) integration adds a Greek Old Testament corpus, a lemma+Strong's annotation layer, a LXX<->MT versification map, and an aggregated MT<->LXX bridge. It reuses the two-form architecture and registry-driven pipeline of the Morpho-Lexical Floor.
54 books of Swete's 1909 Greek OT (full LXX canon including deuterocanon; LXX versification). Chapter files have the same schema as the main corpus but use the greek_lxx field for the verse text. Protocanon books include a refs.mt field (present only when the LXX verse maps to a different MT position or has no MT counterpart).
License: CC0-1.0 (Swete 1909 is Public Domain by age; sourced as PD text, not from any GPL repackaging).
Per-token CoNLL-U files for all 54 LXX books. Each token carries:
FORM(from the LXX verse text),LEMMA(polytonic Greek from LxxLemmas),Strong=G####in MISC where the lemma joins tolexicon/grc.UPOS,XPOS,FEATSare intentionally empty (_). No open LXX morphology source exists today; these columns backfill automatically when STEPBible TAGOT (CC-BY) releases by flipping the registrymorph_schemeentry and rerunninggenerate_morph --testament lxx.Align=matched|unmatchedrecords whether the surface form was found in the LxxLemmas word list for the verse.
License: CC-BY-4.0 (derived from openscriptures LxxLemmas, David Troidl, CC-BY 4.0 -- see docs/LICENSING.md).
data/versification/lxx-versification.json is derived from the Greek/LXX tradition column of STEPBible TVTMS (CC-BY 4.0). data/versification/lxx-versification-supplement.json (CC0) covers chapter-level structural differences not modeled at the verse level by TVTMS: Jeremiah chapter reorder (LXX ~1/8 shorter; Oracles Against the Nations relocated), Greek Esther additions A-F, and Greek Daniel integrated books (Susanna, Song of the Three, Bel).
data/cache/mt-lxx-bridge.jsonl and the mt_lxx DB table are derived projections (rebuildable, not committed). They aggregate verse-level co-occurrence of Hebrew Strong's (H####) and Greek Strong's / lemmas across protocanon LXX-MT verse pairs.
Each bridge row carries: mt_strong, lxx_strong, lxx_lemma, cooccur (verse-pair count), exact (positional-match verse-pairs), positional (word-index-ratio match verse-pairs). This is verse-level co-occurrence, not word-level alignment -- no open CC-BY/PD word-level MT<->LXX alignment exists. Consumers should weight pairs by exact / cooccur ratio; low-count pairs are noise. The bridge is the cross-language handoff for future L2b relation-graph work.
Coverage: 691,240 aggregate rows; protocanon books only (deuterocanon has no MT counterpart).
Full LXX morphology (UPOS/XPOS/FEATS) awaits STEPBible TAGOT (CC-BY 4.0), announced but not yet released. When TAGOT lands it is a drop-in: same morph-code scheme as TAGNT, same normalizer, zero new decoder rules. Backfill: set morph_scheme in data/morph-sources.json to "stepbible_greek" and rerun generate_morph --testament lxx.
Word-level MT<->LXX alignment would upgrade the bridge from verse-level co-occurrence to attested word links, if and when an open CC-BY/PD source appears (the CATSS/Tov alignment is restricted-license and has been rejected).
See docs/LICENSING.md for the per-artifact license map: bible/lxx is CC0; morph/lxx lemma+Strong's is CC-BY (openscriptures LxxLemmas); the versification map is CC-BY (TVTMS) + CC0 (supplement).
The relation graph (L2b) adds a semantic-relation layer on top of the lexicon (L2a). It links lexical entries by five relation types, each edge carrying a rank score (0–65535) and full provenance.
| Relation | Description | Edges | Orientation |
|---|---|---|---|
shared-root |
Etymological kin (same Strong's root) | 80,904 | canonical (src ≤ dst) |
domain-sibling |
Same Louw-Nida or SDBH semantic domain | 1,959,593 | canonical (src ≤ dst) |
cross-language |
MT Hebrew ↔ LXX Greek translation bridge | 691,240 | H#### → G#### (directed by design) |
synonym |
Synonymous meaning (WordNet, Roget, lexica cross-refs, authored) | 6,909,342 | canonical (src ≤ dst) |
antonym |
Antonymous meaning (WordNet, Roget, authored) | 1,955,929 | canonical (src ≤ dst) |
Total: 11,597,008 edges across all relations.
Every edge carries an integer rank in 0..65535. Higher rank = higher confidence / relevance.
DEFAULT_RANK_THRESHOLD = 32768 is the default-view cut-off:
- Edges with
rank >= 32768are in the default view (relations_defaultDB view): ~2,091,882 edges. - Edges with
rank < 32768are materialised in JSONL and the DB but excluded from the default view (low-confidence pairs such as single-verse co-occurrences or coarse domain codes).
Canonical artifacts (version-controlled, human-editable):
relations/authored/synonym.jsonl,relations/authored/antonym.jsonl— hand-authored CC0 truth edges (2 synonym + 2 antonym).
Derived projection (gitignored, deterministically regenerable):
relations/derived/{shared-root,domain-sibling,cross-language,synonym,antonym}.jsonl— five canonical per-rel files produced deterministically bytools/build_relations.py. These files are not committed (gitignored). They are regenerated from version-controlled source files plus auto-downloaded cached sources. Any missing source files (WordNet LMF gz, Roget pg22.txt, BDB XML) are fetched automatically on first run.
python -m tools.build_relations # auto-downloads missing sources + regenerates relations/derived/*.jsonl
python -m tools.build_db # reload relations table + relations_default view
python -m tools.validate_relations # pin check: all counts, provenance, orientation
python -m tools.build_relations is a single command that works from a clean clone with no manual setup: it fetches any missing cached source files and writes all five derived JSONL files. Rebuild is confirmed when python -m tools.validate_relations exits 0 with pinned counts holding.
- Open English WordNet 2024 (synonym + antonym edges, source
open-english-wordnet): "Open English Wordnet 2024, globalwordnet/english-wordnet, CC-BY 4.0, https://github.com/globalwordnet/english-wordnet. Based on Princeton WordNet (CC-BY 4.0, https://wordnet.princeton.edu)." License: CC-BY 4.0. - Roget's Thesaurus 1911 (synonym + antonym edges, source
roget-1911): Public Domain. MICRA Inc. preparation is PD-dedicated. No attribution required. License: CC0. - Strong's Greek / Hebrew cross-refs (synonym edges, sources
strongs-greek,strongs-hebrew,strongs-root): "Public Domain — Strong's Exhaustive Concordance, James Strong 1890. XML by Ulrik Petersen / openscriptures." License: CC0. - Abbott-Smith via STEPBible TBESG (synonym edges, source
abbott-smith): "Data created by www.STEPBible.org based on work at Tyndale House Cambridge (CC BY 4.0). Source: https://github.com/STEPBible." License: CC-BY 4.0. - Brown-Driver-Briggs Hebrew Lexicon (synonym edges, source
bdb): "Brown-Driver-Briggs Hebrew Lexicon (1906), Public Domain. XML by openscriptures, https://github.com/openscriptures/HebrewLexicon." License: CC0. - MACULA Louw-Nida / SDBH domains (domain-sibling edges, sources
louw-nida,sdbh): "MACULA Greek/Hebrew Linguistic Datasets, Clear Bible Inc., CC-BY 4.0. https://github.com/Clear-Bible/macula-greek and macula-hebrew." License: CC-BY 4.0. - MT↔LXX bridge (cross-language edges, source
mt-lxx-bridge): Derived from STEPBible TAGNT/TAHOT + openscriptures LxxLemmas + Swete 1909 LXX (all CC-BY 4.0 or PD). License: CC-BY 4.0. - Hand-authored overlay (source
hand): CC0-1.0 public-domain dedication. License: CC0.
cmd/explorer is a local Go tool for browsing one chapter at a time: parallel edition text, salient lemmas, and their relation-graph connections (see "Relation Graph (L2b)" above), plus verbatim phrase matches and rarity-weighted lexical echoes against the New Testament. It reads the repo working tree directly (internal/explorer/store/fsstore); no database build is required.
go build -o explorer ./cmd/explorer
or run directly with go run ./cmd/explorer <command>.
The Go sources are authored in Go+ (.gp), a strict superset of Go that
emits portable Go. This includes the tests: foo_test.gp emits
foo_gp_test.go, so the go tool still sees a _test.go file. The module
contains no hand-authored .go file at all -- every .go in the tree is
a committed *_gp.go or *_gp_test.go artifact carrying a DO NOT EDIT
header.
Committing the emitted Go is what keeps consumers free of the toolchain: building, testing and vendoring need nothing but the standard Go toolchain, and the commands above work on a fresh clone with no Go+ installed.
Editing a .gp file is the only time regeneration is needed:
make gen # go generate ./...
The toolchain is pinned in go.mod as a Go 1.24+ tool dependency
(tool goforge.dev/goplus/cmd/goplus), so make gen fetches the exact
version rather than relying on whatever is on $PATH. Never edit an emitted
file: it is overwritten on the next generate.
The //go:generate directive itself lives in cmd/explorer/goplus_generate.gp
and reaches go generate through its own emitted goplus_generate_gp.go --
go generate scans Go files only, so a directive in a .gp source is
invisible to it until it has been emitted once. The one consequence is that a
tree with no emitted Go cannot bootstrap with go generate; use the
toolchain directly:
go tool goplus gen ./...
Because Go+ is a superset, the conversion itself was a rename — the language
earns its place where a closed set of alternatives was previously carried as
a string. StoreKind in cmd/explorer/main.gp is the current example:
type StoreKind enum {
FS
DB
}
--store is validated once at the edge by parseStoreKind, so past that
point an unknown backend is unrepresentable and openStore dispatches with
match and no default arm. Adding a third backend is then a build error
naming every stale dispatch site:
non-exhaustive match on StoreKind: missing Memory; add the missing
cases or a 'case _:' arm
rather than a runtime fall-through. The enum lowers to a sealed interface plus one struct per variant, so the emitted Go stays ordinary Go.
Testament is deliberately not an enum: it is the wire format in both
JSON payloads and URLs, and an enum there would fight the serialization
boundary rather than help.
The chapter route is served through
Quicken over
Cadence -- the Elm-architecture and region
transport family the explorer had previously grown its own miniature copy
of. Quicken owns the transport: it streams the shell first, then each
region's content, and its no-script floor is the whole page, which is what
keeps the plain <form method="get"> controls working with JavaScript off.
internal/explorer/render still produces the HTML. The five regions
(cards, echoes, phrases, stats, verses) are cadence.Text over
that existing output rather than semantic trees built from scratch: render
is a golden-tested port of the trusted Python reference, and rewriting it
into browser.Node values would have discarded that to gain nothing the
transport needs. cadence.Tree concatenates statics and dynamics without
escaping, so the markup arrives intact.
The regions are live: changing a filter sends an event over the socket
(long-poll fallback) and every region is re-rendered in place, with no page
reload. The controls carry data-live-region="*" so one change addresses
all five, and data-live-form so the event carries the form's current
values.
With scripting off nothing above happens and the controls are still a plain
<form method="get">, which is why both paths share one parser: the live
event's payload is converted to url.Values and handed to the same
FiltersFromQuery a query string goes through, so the two cannot interpret
the same controls differently.
One document serves all five regions per change. Each region handles the
broadcast independently, so a single-entry cache in quickenui collapses
what would otherwise be five identical BuildDocument calls -- store reads
plus salience, phrase and echo detection -- into one.
render.Shell is the seam: the same template as render.Page, with each
region body replaced by Quicken's slot. One template serves the hosted
page, the static exporter and the golden test.
The explorer reads relations/derived/*.jsonl, which is gitignored and not part of a fresh clone. Build it once with:
python -m tools.build_relations
explorer serve checks for this at startup and refuses to start with a message naming this exact command if the derived relations are missing.
explorer serve [--addr localhost:8724] [--store fs|db] [--repo .]
Starts a local HTTP server, default http://localhost:8724, bound to localhost only (no external network exposure; pass --addr to override). GET / redirects to /ot/PSA/8; GET /{testament}/{book}/{chapter} (e.g. /ot/PSA/8) renders a chapter page; GET /api/chapter?testament=...&book=...&ch=... returns the same data as JSON for the in-browser client. --repo points at the corpus repo root (default the current directory). --store selects the storage backend: fs (default, reads the working tree directly) or db (a later task's SQLite-backed adapter; selecting it today exits with a clear "lands in a later task" error rather than a confusing failure downstream).
The filter controls on every chapter page are a plain <form method="get">, so they work with JavaScript disabled: submitting the form reloads the page with the new filters as query parameters, server-rendered. The page is hosted on Quicken (see "Hosting: Quicken" above), whose no-script floor is the whole document, so the form-driven path needs no client at all; the only script the page loads is Quicken's own region shim.
explorer render <testament> <book> <chapter> [--store fs|db] [--out file] [--repo .] [filter flags]
Writes one chapter as a single self-contained HTML file (inline CSS, no external requests, no script): to stdout by default, or to --out file. --store selects the storage backend the same way as serve, fs (default) or db. The three positional arguments must come before any flags, for example:
explorer render ot PSA 8 --out psalm8.html --rank-min 20000
Filter flags mirror the server's query parameters: --rank-min, --kinds (comma-separated), --per-kind-cap, --domain-kind-cap, --lemma-count, --lemma-sort, --phrase-min-len, --phrase-max-subs, --echo-top. Output is deterministic: identical data and flags always produce byte-identical HTML.