Metadata-Version: 2.4
Name: genealogy-kg
Version: 0.6.0
Summary: KGModule for genealogical knowledge graphs built from GEDCOM files
License-Expression: Elastic-2.0
License-File: LICENSE
Keywords: knowledge-graph,genealogy,gedcom,family-tree,sqlite-vec,semantic-search,kgmodule
Author: Eric G. Suchanek, PhD
Author-email: suchanek@flux-frontiers.com
Requires-Python: >=3.12,<3.14
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Sociology :: Genealogy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Provides-Extra: adapter
Provides-Extra: viz
Provides-Extra: viz3d
Requires-Dist: PyQt5 (>=5.15.0) ; extra == "viz3d"
Requires-Dist: click (>=8.1.0,<9)
Requires-Dist: ged4py (>=0.5.2)
Requires-Dist: kg-rag (>=0.17.0) ; extra == "adapter"
Requires-Dist: kgmodule-utils[mcp,semantic,sqlite-vec] (>=0.29.0)
Requires-Dist: kgmodule-utils[viz3d-qt,viz3d-render] (>=0.29.0) ; extra == "viz3d"
Requires-Dist: kgmodule-utils[viz] (>=0.29.0) ; extra == "viz"
Requires-Dist: markdown (>=3.6) ; extra == "viz3d"
Requires-Dist: param (>=2.0.0) ; extra == "viz3d"
Requires-Dist: plotly (>=5.14.0) ; extra == "viz"
Requires-Dist: pyvistaqt (>=0.11.0) ; extra == "viz3d"
Requires-Dist: quiltwright (>=0.17.0) ; extra == "viz3d"
Requires-Dist: streamlit (>=1.35.0) ; extra == "viz"
Project-URL: Homepage, https://github.com/Flux-Frontiers/genealogy_kg
Project-URL: Repository, https://github.com/Flux-Frontiers/genealogy_kg
Description-Content-Type: text/markdown

# GenealogyKG

[![Python](https://img.shields.io/badge/python-3.12%20%7C%203.13-blue.svg)](https://www.python.org/)
[![License: Elastic-2.0](https://img.shields.io/badge/License-Elastic%202.0-blue.svg)](https://www.elastic.co/licensing/elastic-license)
[![PyPI](https://img.shields.io/pypi/v/genealogy-kg.svg)](https://pypi.org/project/genealogy-kg/)
[![Version](https://img.shields.io/badge/version-0.6.0-blue.svg)](https://github.com/Flux-Frontiers/genealogy_kg/releases)
[![CI](https://github.com/Flux-Frontiers/genealogy_kg/actions/workflows/ci.yml/badge.svg)](https://github.com/Flux-Frontiers/genealogy_kg/actions/workflows/ci.yml)
[![Docs](https://github.com/Flux-Frontiers/genealogy_kg/actions/workflows/docs.yml/badge.svg)](https://flux-frontiers.github.io/genealogy_kg/)
[![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.22182369-blue.svg)](https://doi.org/10.5281/zenodo.22182369)
[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
[![Corpus](https://img.shields.io/badge/corpus-97%20trees-orange.svg)](corpora/entries/NOTICE.md)
[![People](https://img.shields.io/badge/people-13.8k-green.svg)](corpora/entries/NOTICE.md)
[![Families](https://img.shields.io/badge/families-6.1k-green.svg)](corpora/entries/NOTICE.md)

A knowledge graph over GEDCOM family-history files: people, families, events,
places and sources as nodes, lineage as edges, and a sqlite-vec index for
natural-language search. Built on the KGRAG fleet's shared `kgmodule-utils`
SDK, so it federates with the other knowledge graphs and speaks the fleet's
temporal contract.

**See [docs/USAGE.md](docs/USAGE.md) for the complete guide** -- every CLI
command, the MCP server's tool reference, the curated corpus, and the
living-person privacy model, with real examples. The docs are also published
at [flux-frontiers.github.io/genealogy_kg](https://flux-frontiers.github.io/genealogy_kg/).
[The Family orchard](https://flux-frontiers.github.io/kpress_family/) is a
browser app over `genkg export-web` output, showing three public trees.

*Author: Eric G. Suchanek, PhD -- Flux-Frontiers, Liberty TWP, OH*

> **Status: beta (0.6.0).** Build, query and pack, lineage walks, analysis,
> snapshots, the 2-D charts, the 3-D hourglass tree with Looking Glass quilts,
> the web and Swift exports, the `genkg` CLI and the `genkg mcp` server work
> end to end, and have been run against the 97-tree curated corpus. Living
> people are redacted by default, and `pack()` never returns a submitter's
> contact record. KGRAG federates a store as kind `genealogy`. See
> [CHANGELOG.md](CHANGELOG.md) for what each release added and
> [docs/DESIGN.md](docs/DESIGN.md) for the phased build history.

## Overview

GenealogyKG reads a GEDCOM 5.5 or 5.5.1 file and builds:

- a SQLite graph (`.genealogykg/graph.sqlite`) with `person`, `family`,
  `event`, `place` and `source` nodes linked by `CHILD_IN`, `SPOUSE_IN`,
  `PARENT_OF`, `MARRIED_TO`, `HAS_EVENT`, `OCCURRED_AT`, `CITES` and
  `WITHIN` (place hierarchy: `Cincinnati, Hamilton, Ohio, USA` is `WITHIN`
  `Hamilton, Ohio, USA`, and so on up to `USA`) edges
- a sqlite-vec index (`.genealogykg/vectors.sqlite`) over a prose summary of
  every record, so "chemists born in Cincinnati" finds Robert Hartwell
- `occurred_start` / `occurred_end` metadata derived from birth, death and
  marriage dates, so a federated KGRAG query can scope the graph by time

`pack` returns the original GEDCOM record behind each hit, with line numbers.
The source file is read in place and never copied into the store.

## Quick start

```bash
pip install genealogy-kg

# Build the graph (creates .genealogykg/ in the current directory)
genkg build --source family.ged

# Search
genkg query "emigrated from Yorkshire"

# Source-grounded snippets for an LLM context window
genkg pack "Hartwell marriages" --output context.md

# Lineage walks
genkg ancestors I7 --generations 3
genkg descendants I1

# Family trees as self-contained HTML (needs the `viz` extra)
genkg viz I1 --output tree.html
genkg viz I1 --view network --color-by generation --output family.html

# A 3-D family tree: ancestors as roots below the ground, descendants as the
# canopy above (needs the `viz3d` extra)
genkg viz3d I7
genkg quilt I7 --ancestors 3 --descendants 2

# Data files for The Knowledge Press: The Family. Both refuse unless the store
# was built with the living-person filter on (see "Living people" below).
genkg export-web --out family-web --living-cutoff 100
genkg export-swift --out family-swift --living-cutoff 100 --embedder-from <dir>

# Generation depth, surnames, date coverage, people with no family links
genkg analyze

# Point-in-time metrics, tracked in git
genkg snapshot save
genkg snapshot list

# MCP server for Claude Code and other MCP clients
genkg mcp --repo .

# No GEDCOM of your own? Build one of the 97 curated trees shipped in this
# repo -- see "The curated corpus" below.
genkg corpus ingest --genre samples --no-register
genkg descendants I0001 --repo corpora/entries/samples/bronte   # the Brontë family
```

## Installation

### From PyPI

```bash
pip install genealogy-kg
pip install "genealogy-kg[adapter]"   # + kg-rag, for KGRAG federation
pip install "genealogy-kg[viz]"       # + plotly/pyvis, for `genkg viz`
pip install "genealogy-kg[viz3d]"     # + PyVista/PyQt5, for `genkg quilt`/`viz3d`
```

### Local development

```bash
git clone https://github.com/Flux-Frontiers/genealogy_kg.git
cd genealogy_kg
poetry install --with dev
poetry run pytest
```

Dev tooling is a Poetry group, not an extra: `pip install genealogy-kg[dev]`
does not exist. To also get the `dockg` and `pycodekg` CLIs that index this
repo itself, run `poetry install --with dev,kg`.

## Configuration

`genkg build --source` records the file it used in
`.genealogykg/config.json`; later builds reuse it. To pin sources in the
project instead, list them in `pyproject.toml`:

```toml
[tool.genealogykg]
sources = ["family.ged"]
```

`.gitignore` excludes `*.ged` outside `tests/fixtures/`. GEDCOM exports
contain personal data about living people; keep them out of version control.

### Living people

The living-person filter is on by default. With nothing configured, a build
behaves as if `pyproject.toml` said:

```toml
[tool.genealogykg]
sources = ["family.ged"]
living_cutoff_years = 100
unknown_birth_policy = "redact"
```

`living_cutoff_years = 0` turns the filter off, for a private store only.

Anyone with no death or burial record who was born within the last 100
years is stored as a bare `person` node named `Living`: their lineage
edges and sex are kept so trees still walk through them, but their name,
dates, events, notes and citations are dropped, and their name is withheld
from every family, spouse and parent mention too. A family with a living
spouse keeps its members but not its marriage details.

`unknown_birth_policy` controls records that have neither a usable birth
date nor a death/burial record. The default, `"redact"`, treats them as
living; this also hides historical people whose dates are simply
incomplete. `"keep"` preserves them, at the cost of exposing any living
person whose record carries no dates. A death or burial record always counts
as affirmative evidence that the person is not living.

`pack` never shows a submitter (`SUBM`) record -- the compiler's name,
address, phone and email -- whether or not the filter is on.

A store built before redaction was the default stays unredacted until it is
rebuilt. `pack` reads the GEDCOM file in place, so share the `.genealogykg/`
store without the `.ged` file.

### What this repository holds

The filter governs what the tool returns: `query`, `pack`, the MCP server
and the exports. It does nothing for the GEDCOM files themselves. The 97
trees in `corpora/entries/` are public GEDCOMs from
[D-Jeffrey/gedcom-samples](https://github.com/D-Jeffrey/gedcom-samples) and
the Gramps and GEDitCOM samples, committed as published, except that their
submitter records are withheld by `scripts/scrub_submitters.py`. Some of
them (royal92, Kennedy, Tolkien, the US presidents) name people who are
alive today. Never commit a personal or family GEDCOM.

`export-web` and `export-swift` never trust the store. Each re-reads the
GEDCOM under its own cutoff (`--living-cutoff`, default the pyproject value;
`--unknown-birth` defaults to `redact`) and refuses if the store holds anyone
that cutoff treats as living under anything but `Living`. After writing, each
scans its own output for those people's real names and refuses again on a
hit, so a note in a dead relative's record that names a living child stops
the export instead of shipping. A name a dead ancestor also bears cannot be
scanned for, since the ancestor's own page carries it. `--include-living`
skips both checks, for a private copy only, and is recorded in the output.

### Git hook

`genkg install-hooks` writes a `pre-commit` hook that runs the repo's
`pre-commit` checks on every commit. Set `GENKG_SNAPSHOT=1` on a
commit to also rebuild the store and save a snapshot; that is off by
default because a snapshot staged into the commit it describes can never
carry that commit's tree hash.

### The curated corpus

`corpora/entries/<genre>/<slug>/*.ged` is a committed, curated set of 97
public GEDCOM trees across 10 genres (royalty, US presidents, corporations,
fictional characters, and more) -- unlike the benchmark corpora below,
these ship *in the repo* and are safe to build against directly, since
safety is enforced at the query/pack/MCP boundary rather than by curating
which files are let in. See
[corpora/entries/NOTICE.md](corpora/entries/NOTICE.md) for provenance and
licensing.

```bash
genkg corpus survey                    # which entries are built, by genre
genkg corpus ingest --genre samples    # build (and register with KGRAG)
```

See [docs/USAGE.md](docs/USAGE.md#the-curated-corpus) for the full
`genkg corpus` reference.

### Benchmark corpora

`./scripts/fetch_corpora.sh` downloads public GEDCOM files (the 1992
European royalty file, the US presidents file, the GEDCOM 5.5 torture test,
and a 200,000-person scale benchmark) into the gitignored `corpora/`
directory -- everything under it except `corpora/entries/`, which is
committed. [docs/CORPORA.md](docs/CORPORA.md) lists each file, its
provenance and licence, and what it exercises.

## Storage

```
.genealogykg/
  graph.sqlite     nodes and edges
  vectors.sqlite   sqlite-vec index (BAAI/bge-small-en-v1.5, 384-d)
  snapshots/       point-in-time metrics, tracked in git
  config.json      source path used by the last build
```

## KGRAG federation

GenealogyKG registers with [kg-rag](https://github.com/Flux-Frontiers/kgrag)
as kind `genealogy` (`KGKind.GENEALOGY`) -- `genkg corpus ingest` is the
usual way entries get registered. Once registered, `kgrag query` and `kgrag
pack` include people, families and events from every registered
GenealogyKG store alongside the fleet's other knowledge graphs, and a
federated query can scope by time using the `occurred_start`/`occurred_end`
metadata derived from birth, death and marriage dates.

## Citation

```
Suchanek, E. G. (2026). GenealogyKG: Genealogical Knowledge Graph
(Version 0.6.0) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.22182369
```

```bibtex
@software{suchanek_genealogykg_2026,
  author    = {Suchanek, Eric G.},
  title     = {GenealogyKG: Genealogical Knowledge Graph},
  year      = {2026},
  version   = {0.6.0},
  url       = {https://github.com/Flux-Frontiers/genealogy_kg},
  doi       = {10.5281/zenodo.22182369},
}
```

## License

Elastic License 2.0. See [LICENSE](LICENSE).

