Dataset Distribution
How the CC0 datasets are packaged and mirrored to HuggingFace and Kaggle — the build_distribution.py packager, the upload flow, and how to update a mirror.
On this page
The Wheel of Heaven datasets live primarily on the API (/v1/datasets/, /v1/graph/) with human-facing landing pages on www. Because they are CC0, we also mirror them to high-authority data platforms — for backlinks, for reach into the ML and data-science communities, and for a second discovery surface. This page documents that packaging and upload pipeline.
Why HuggingFace + Kaggle (and not a DOI repository)#
We evaluated Zenodo and the other DOI-minting archives first. Zenodo automatically de-ranks uploads from unverified individual accounts — hiding them from its own search while leaving them visible to duplicate-checkers — which would defeat the discoverability goal the mirrors exist to serve. HuggingFace and Kaggle give high-authority backlinks and a real audience without that risk, and Kaggle is itself a Google Dataset Search source, so it restores the second Dataset-Search listing without a DOI. If academic DOIs become worthwhile later, Harvard Dataverse and OSF are the individual-friendly, Dataset-Search-indexed options (both mint DataCite DOIs, neither de-ranks individuals).
The packager#
api.wheelofheaven.world/scripts/build_distribution.py assembles a self-contained upload folder per dataset per platform. Stdlib only; no network and no accounts, so it is fully runnable offline.
python scripts/build_distribution.py --kaggle-user <handle>Output lands under scripts/dist/ (git-ignored):
scripts/dist/
├── huggingface/<slug>/ # README.md dataset card + data files
└── kaggle/<slug>/ # dataset-metadata.json + data filesThe dataset list and metadata (title, subtitle, blurb, keywords, columns, files, landing URL) live in the DATASETS table at the top of the script — add an entry there to include a new dataset in the mirrors.
- HuggingFace card — YAML frontmatter (
license: cc0-1.0,pretty_name,tags,language) plus a markdown body with the record count, column list, provenance, and a citation line. - Kaggle metadata —
dataset-metadata.jsonwithtitle, a 20–80-charactersubtitle(Kaggle enforces that range — the packager fails loudly if a subtitle falls outside it),licenses: CC0-1.0,keywords, and oneresourcesentry per file. Theidis<owner>/<slug>, filled from--kaggle-user.
HuggingFace upload#
The datasets live under the wheelofheaven organization. Uploading uses the hf CLI (the modern replacement for the deprecated huggingface-cli):
pip install -U huggingface_hub
hf auth login # paste a WRITE-scope token
for s in content-graph flood-myths divine-council-index theomachy-crossrefs world-ages prophets-and-religions myth-index aarne-1910-tale-types; do
hf upload wheelofheaven/$s scripts/dist/huggingface/$s --repo-type=dataset
donehf upload auto-creates the dataset repo on first push.
Collections. The org page is organized by two HF collections — Comparative Mythology & Classification (the 9 comparative/classification datasets) and Parallel Scripture Corpora (the 20 translation books) — created via huggingface_hub.create_collection / add_collection_item (note: collection descriptions max 150 chars). Add every new dataset to its collection as part of the publish checklist.
Dataset-viewer gotcha. With both a .csv and a .json in the repo the viewer may pick the JSON builder — and the API’s JSON files are single objects (a columns + rows envelope) that pyarrow cannot parse, which kills the viewer (is-valid all false, SplitsNotFoundError). The packager therefore emits a configs: block in every card pinning the viewer to the CSV (data_files: <slug>.csv); content-graph, which has no tabular file, is the exception. Diagnose with https://datasets-server.huggingface.co/is-valid?dataset=wheelofheaven/<slug> and /splits?dataset=…. Verify via the public API: https://huggingface.co/api/datasets?author=wheelofheaven.
Namespace note. HuggingFace users and organizations share one namespace, so standing up the wheelofheaven org required renaming the personal account to zarazinsfuss first — a one-time, self-serve username change — to free the wheelofheaven handle. Do not delete an account to free a handle: a deleted namespace returns to the public pool immediately and can be re-registered by anyone.
Kaggle upload#
The datasets are live under the personal account zarazinsfuss. Kaggle users and organizations do not share a namespace, so no renaming was needed — but note Kaggle has suspended organization creation for regular users, so there is no wheelofheaven Kaggle org; the personal account is the owner (this is the Kaggle norm and costs nothing in discoverability). Set --kaggle-user zarazinsfuss when packaging, then:
pip install kaggle # needs a phone-verified account + API credential (see below)
for s in content-graph flood-myths divine-council-index theomachy-crossrefs world-ages prophets-and-religions myth-index aarne-1910-tale-types; do
kaggle datasets create -p scripts/dist/kaggle/$s --public
doneThree gotchas:
--publicis required.kaggle datasets createdefaults to private.- Credential. The CLI authenticates from
~/.kaggle/kaggle.json(classic username+key) or the newer~/.kaggle/access_token— the Kaggle CLI (≥2.2) reads either. A phone-verified account is required to publish. - Tags. Kaggle uses a controlled tag vocabulary; free-text keywords in
dataset-metadata.jsonare rejected on upload (“not valid tags”) — the dataset is still created, minus the invalid tags. Verified-valid slugs for this corpus:textandhistory(for the comparative datasets; the translation books usenlp, translation, text).culture,religion,literature,digital-humanitiesare all invalid. The comparative datasets are published withtext, history(usability ~0.59).
Updating a mirror#
When a source dataset changes (a regenerated graph, an edited CSV):
- Rebuild the packages:
python scripts/build_distribution.py --kaggle-user <handle> - HuggingFace — re-run
hf upload …for the changed slug; it commits a new revision to the existing repo. - Kaggle —
kaggle datasets version -p scripts/dist/kaggle/<slug> -m "notes"(useversion, notcreate, once the dataset exists).
Translation datasets#
The CC0 books of the Wheel of Heaven Translation Program (data-library/*-woh) are published as HuggingFace datasets by a separate packager, data-library/scripts/build_translation_datasets.py (stdlib only, run from the data-library repo root). Per book it emits a verse-aligned parallel corpus:
<slug>.jsonl— one row per verse:ref,chapter,verse,original(source script),original_lang,transliteration,english(WoH translation),reference_english(an aligned public-domain reference translation — empty where none exists),reference_version,reference_license,commentary,glossary_refs,witness_primary,witness_secondary— joined fromchapter-*.json(translation side) andsource-*.json(source apparatus) byrefId.glossary.json— the per-book translation glossary ($schemastripped; the term container istermsorentriesdepending on the book).README.md— the dataset card (methodology, source provenance, sign-off status; internal batch codenames like “Ship A/B” are scrubbed).
Reference translation. Each -woh book has an aligned public-domain sibling in data-library (e.g. genesis beside genesis-woh), and load_reference() joins it into reference_english on (chapter, verse) — so a row shows the Wheel of Heaven rendering against a neutral control (elohim as a plural, taninim as dragons, ruach as breath rather than Spirit). 11 of the 20 books get one: ASV 1901 for the biblical set, the World English Bible for Daniel, and R. H. Charles’s 1917 edition for Enoch (whose versification diverges — only ~24% aligns). Jubilees, Shiur Qomah, the Qurʾān, and the non-biblical corpus (Theogony, the Sumerian poems, the King List) ship reference-less — no aligned public-domain English edition, or (Isaiah) one whose licence can’t be verified — with an honest card note. The join refuses any reference whose licence isn’t public-domain/CC0, so the corpus stays honestly mixed-license: the Wheel of Heaven layer (translation, commentary, glossary) is CC0-1.0, the reference column is public domain.
Selection gates. discover_books() ships a -woh book only if it (1) is CC0 (versionLicense == "CC0-1.0" — refuses anything else), (2) is not in HELD (three living-tradition scriptures parked for a rights review), and (3) has translated verses (the packager skips stubs and source-only books; line-based poem schemas — lines[] instead of paragraphs[], e.g. Theogony — are supported). The Raëlian canon is © International Raëlian Movement (not CC0) and excluded by the license gate. Each card gets an honest review-status line (signed off / reviewed per chapter / pending verification / draft) via review_status() — never claiming a sign-off a book lacks. 20 books live (5,771 aligned verses). Upload the same way:
hf upload wheelofheaven/<slug> scripts/dist-hf/<slug> --repo-type=datasetKaggle mirror. --kaggle-owner <owner> also emits dist-kaggle/<slug>/ — the same .jsonl + glossary.json plus a Kaggle dataset-metadata.json — a second Google-Dataset-Search surface. The 20 books are live under zarazinsfuss; there is no wheelofheaven Kaggle org (Kaggle suspended self-serve org creation for regular users, so unlike HuggingFace this stays on the personal account):
python scripts/build_translation_datasets.py --kaggle-owner zarazinsfuss
kaggle datasets create -p scripts/dist-kaggle/<slug> --public # first publish
kaggle datasets version -p scripts/dist-kaggle/<slug> -m "notes" # later updatesTwo Kaggle gotchas: titles must be 6–50 chars and subtitles 20–80 (the packager auto-fits both), and Kaggle caps category-tags — passing more than a few valid tags trips “exceeded the max category limit” (which still creates the dataset, minus tags), so the keyword set is pinned to nlp, translation, text.
Reciprocal links. Each -woh book’s /library/<slug>/ reader page links back to its datasets via [extra] hf_dataset and [extra] kaggle_dataset fields (rendered by library-book.html as “Available as a CC0 dataset on Hugging Face · Kaggle →” after the lede — the reader template does not render the page’s markdown body, so the links must be frontmatter fields, not body text). See frontmatter → Library book.