Will Hubbard

AI coding agents for genealogy

Since July I’ve been researching my family tree with Claude Code and ChatGPT Codex. Neither one is built for genealogy. They’re coding assistants. That turned out to be exactly why they’re good at it.

Ancestry, FamilySearch, and most other genealogy sites can export your tree as a GEDCOM file, which is plain text structured a lot like code. So I exported mine, put it in a Git repository backed up to a private GitHub repo, and pointed both AI tools at it.

Three months in, the tree has about 2,700 people, including 1,365 direct ancestors so far, with a written record of the evidence behind each link. The bigger surprise was how much I learned about the people themselves. I found out my last name should really be Chase, that I descend from at least 26 Mayflower passengers, and that one of my ancestors broke out of an English prison during the Revolution.

The Claude and Codex agents didn’t just make my tree bigger. They made it a lot stronger. A lot of what I had came from other people’s trees, and the agents went and found the actual records behind each link, then read them, often in other languages, like the old French parish registers of Quebec. Plenty of links got confirmed, some got corrected, and a few got cut entirely.

What a GEDCOM file is

GEDCOM is the standard format for moving a family tree between programs, and every major genealogy site can import and export it. FamilySearch maintains the spec. Each line has a level, a tag, and a value, and records point at each other by ID. Here’s a trimmed-down record for one of my ancestors:

0 @I9686@ INDI
1 NAME Marguerite /Collet/
1 BIRT
2 DATE ABT 1653
2 PLAC Paris, Ile-de-France, France
1 OCCU Fille du roi
1 FAMC @F9353@
1 FAMS @F9350@

FAMC points at the family she was born into, and FAMS at the family she started. A GEDCOM is basically a database written as text, so the agents could read it directly, write Python to query it, and check it the way you’d check code, looking for links that point at nothing or someone who accidentally became their own ancestor. My file is about 2 MB, which is too much to paste into a chat but easy for a tool that can run scripts against it.

Setting up my family tree like a Git repo

The more I worked on the tree, the more it felt like a software project.

Genealogy Git
A research question, like “who were Francis Schoen’s parents?” A branch
Bringing a finished line of research back into the tree A merge
Two lines of research that changed the same records A merge conflict
Why you believe a link, and what you ruled out A commit message
Undoing a parent link that turned out to be wrong A revert

So I set it up that way. One source file gets edited, and a build script generates two copies from it: a master with everything, and a trimmed copy for uploading to Ancestry. Research happens on branches named after the question, like francis-schoen or eliza-steele-mother, and when two agent sessions run at once, each gets its own Git worktree so they can’t overwrite each other.

A main branch from July 24 to October 14, 2026, with four research branches splitting off and merging back. Before francis-schoen merged, both sides had used the same source ID, so it was renumbered first. The main branch feeds build.py, which writes a full master GEDCOM and a trimmed upload copy for Ancestry.

Merge conflicts happened too, and they were sneakier than in code. Two parallel sessions would each give the next free ID to a different new record. Resolve that the obvious way and everything still looks valid, but now some people are citing the wrong document. So there’s a script that checks for ID collisions before any branch merges.

A few other things made it work across two different agents. Claude Code reads CLAUDE.md and Codex reads AGENTS.md, and both point to the same rules. Every change gets a changelog entry saying why, which document proved a link and what it ruled out. And every time something went wrong, the agent wrote a short lesson into the repo, like “two spellings are two searches,” so the next session starts out already knowing it. There are 86 of them now.

What I learned about my family

I went into this expecting to clean up some dates. I didn’t expect to actually get to know these people. Some of these stories my family already knew, like my great-grandfather’s adoption and our connection to William Bradford, and the agents found the records behind them. But a lot of them had been completely forgotten, sitting in old registers, court books, and newspapers no one had looked at in a century.

AI hallucinations are real, but I’m confident in all my findings. Every story is tied to a specific record, like a page in a probate book or a dated newspaper column, and I can open any of them and read it myself, like the two below.

My last name should be Chase

My great-grandfather was born John Cushing Chase in 1904. His mother died a few weeks later, and he was raised by her sister Anna and her husband, Ray Spencer Hubbard. I always knew that story, but an agent flagged that my tree said “adopted” with no record behind it, went looking, and found the actual decree:

The January 10, 1912 adoption decree from the Norfolk County Probate Court. Ray Spencer Hubbard and his wife Anna Bradford Hubbard petition to adopt John Cushing Chase, child of Samuel Frye Chase and Elizabeth Bradford Chase, deceased. The father, the surviving parent, has consented, and the child’s name is changed to John Chase Hubbard.

The line that got me is “the father, the surviving parent of said child, has consented thereto.” His father, Samuel Frye Chase III, lived another 25 years, and his obituary still lists “John Hubbard” as one of his kids. I still don’t know why he let him go.

William Bradford, my namesake

My full name is William Bradford Hubbard III, named for Governor William Bradford of Plymouth Colony, and the agents confirmed he’s my 10th-great-grandfather through my great-grandfather’s mother. So the Hubbard came from an adoption, but the Bradford is real. He was an orphaned Yorkshire farm boy who crossed on the Mayflower in 1620, lost his wife overboard off Cape Cod, and was picked to lead the colony after its first governor died that spring. He ran Plymouth for most of the next 36 years, hosted the 1621 harvest feast we now call the first Thanksgiving, and wrote Of Plymouth Plantation, the main firsthand account of the Pilgrims.

At least 26 Mayflower passengers

I knew I had deep colonial roots, but not how deep. In addition to William Bradford, I descend by blood from at least 25 more of the Mayflower’s 102 passengers, on both my mom’s and my dad’s sides, including:

  • John Alden and Priscilla Mullins (my 10th-great-grandparents), the couple from Longfellow’s poem. I descend from them three separate ways.
  • Stephen Hopkins (my 10th-great-grandfather), who had already survived the Bermuda shipwreck that inspired The Tempest and a death sentence for mutiny.
  • Peregrine White (my 10th-great-grandfather), born on the Mayflower in Provincetown Harbor, the first English baby born in New England.
  • John Billington (my 11th-great-grandfather), hanged for murder in 1630, the colony’s first execution.
  • Edward Doty (my 10th-great-grandfather), who fought New England’s first duel in 1621.

A few more interesting stories

  • Capt. Thomas Barker (my 6th-great-grandfather) escaped from an English prison. He fought at Bunker Hill, went privateering, and was captured in 1777 and sent to Old Mill Prison in England, where the prisoner list marks him “ran away.” Eighteen years later, fighting off pirates on the way home from Spain, his crew ran out of cannon shot, and someone yelled, “Shove in the knives, forks and spoons!” They loaded the cannons with silverware and won.

  • Marie Louise (Blanchette) White (my 3rd-great-grandmother) remembered Paris. Claude spent a full day failing to find her parents. Then the agents found a 1929 newspaper interview with her on her 95th birthday that named them. Fourteen minutes later, Claude had her baptism from a handwritten French register, and by the end of the day it had traced her line back to a fille du roi, one of around 800 young women the French king sent to New France to marry, who was christened in Paris. The article said her grandparents came from Paris. It was off by five generations, but she was right about Paris.

    A page of the Quincy Evening News from February 26, 1929, with the headline “Mrs. Doric White At 95, Believes ‘Work Never Killed Anybody,’” a portrait captioned Mrs. Doric White, and an article saying she was born in St. Hyacinth, Canada, in 1834, the daughter of John and Rosalie (Besant) Blanchette, and that her grandparents had emigrated from Paris.

  • Aquila Chase (my 10th-great-grandfather), the first Chase in America, was hauled into court in 1646 for picking peas on the Sabbath.

  • Rebecca Cornell (my 11th-great-grandmother) was found burned to death by her fireplace in 1673. Her son was hanged for it, largely because her brother swore her ghost appeared at his bedside.

  • Caleb Buffum (my 10th-great-grandfather), a Salem Quaker, made coffins for people hanged in the 1692 witch trials.

  • Samuel Gorton (my 11th-great-grandfather), a religious rebel who founded Warwick, Rhode Island, named his daughter Maher-Shallal-Hashbaz.

  • Humphrey Atherton (my 12th-great-grandfather), who commanded the Massachusetts militia and persecuted Quakers, was killed in 1661 when his horse ran into a cow on Boston Common.

  • Capt. William Stevenson (my 4th-great-grandfather) was forced into the British navy before the War of 1812, joined the U.S. Navy as soon as he got out, and walked home to Maine after his discharge.

  • Malachi Harmon (my great-great-grandfather) married two sisters, one after the other, and supposedly told his mother-in-law he’d have married a third if she’d had one.

  • Gen. Joseph Frye (my 7th-great-grandfather) survived the 1757 massacre at Fort William Henry, the one in The Last of the Mohicans, had Fryeburg, Maine named after him, and in 1776 wrote to George Washington to resign from the Continental Army.

Other people’s trees are mostly copies

A lot of what’s on genealogy sites is wrong, and it spreads because copying is so easy. Ancestry suggests a parent from someone else’s tree, you click accept, and someone copies it from you. Two people with the same name get merged into one, a guessed date gets repeated forever, and after a few rounds the same mistake shows up on five sites and starts to look like a fact.

This is where the agents helped the most. It didn’t care how many trees agreed. It wanted the actual record that said who someone’s parents were, and anything that only rested on other people’s trees got marked as provisional. Using those rules, it cut entire branches that turned out to be wrong, including a supposed line to royalty, and confirmed plenty of others I’d never been sure about.

Going wide first, then deep

Every generation back doubles the number of ancestors, and 10 generations back there are 1,024 slots in that generation alone. So I split the project in two.

The first nine generations are a horizontal play. The goal is to identify everyone out to my seventh-great-grandparents, with a real record behind every parent link. From generation 10 on, it flips to a vertical play. That far back, records get thin and trees get unreliable, so I pick a line and follow it as deep as the records go, wherever I get curious. The tree’s own numbers show where that line falls:

Generation back Possible ancestors Found Parent links backed by a record
1–5 62 62 All but my living family
6 64 61 100%
7 128 93 82%
8 256 122 83%
9 512 143 74%
10 1,024 166 61%
11 2,048 234 13%

The horizontal part isn’t finished, and providing direct evidence for generations 7 through 9 is the next big push. But the evidence mostly holds up through generation 10 and then falls off a cliff, which is exactly where going wide stops making sense. It also makes the project more fun: a solid foundation I can trust, and then the freedom to chase whatever catches my attention. Most of the stories above came from those deep dives.

Getting Ancestry to accept the file

This was by far the most frustrating part. When Ancestry’s importer rejects a GEDCOM, it gives the same short error every time, with no line number or reason. The agents tested eleven theories about what it objected to, and every one was disproven by an upload.

They eventually figured out that Ancestry rejects files over the text inside individual citations, even when the file is completely valid. This was one of them:

small pox, b. Kingston, PARENTS "EBENEZER & PRISILLA DA[WS]"

The method was basically git bisect: upload a known-good file, then a version with half the changes, and keep splitting until you’re down to one string. Now every upload carries one change at a time, and every rejected string goes on a list that a Git hook blocks from coming back.

The other big limitation is photos. A GEDCOM is just text, so none of the record images and family photos I’ve collected show up when I upload the tree to Ancestry or FamilySearch. They live in the repo on my computer and in GitHub, and if I want one online, I have to attach it by hand.

Letting the agents use the browser

The research really took off once the agents could use a browser. With the Claude in Chrome extension, Claude worked inside my own browser, where I was already signed in to Ancestry and FamilySearch. It searched census records, read scanned registers, and went through Ancestry’s hints. Instead of clicking through search pages, it ran the sites’ own search requests dozens at a time, and when handwriting was hard to read, it pulled the image at full resolution and zoomed in.

Letting Claude work through DNA matches was a game changer. My mom’s AncestryDNA kit has about 69,000 matches, far more than I could ever go through by hand. Claude could. DNA is evidence of actual shared descent, not just a name and a place that fit, so it can settle questions that documents argue about for days. In one case, 17 matches through a single couple confirmed a parentage that had taken two days of records to work out. A 20-minute sweep of one generation turned up DNA support on six of its eight family lines. And searching the match list by surname, instead of relying on Ancestry’s ThruLines suggestions, found two siblings of one ancestor that nobody had traced in decades.

Names were one of the hardest parts. They get misspelled, misheard, translated, and mistranscribed constantly. My 3rd-great-grandmother Ann Maria shows up as Varnum, Vernum, Yurnum, and Vernun across her own kids’ records. My 4th-great-grandfather Francis Schoen was only findable once the agent searched for Schön instead of Schoen. On my Quebec side, LeBlanc became White in Massachusetts, and Blanchet became Blanchette and Blanchard. The agents were really good at spotting these variants and then checking whether they were the same person, using details like ages, spouses, and kids, or two different people with the same name. It split apart two men named Benjamin F. Rogers, both born in Georgia around 1842, who had been merged into one. Only one of them is my 3rd-great-grandfather.

It also learned that genealogy search tools fail silently. A search with a bad setting just comes back empty, which looks exactly like the record not existing. So before writing down that something doesn’t exist, it runs a search it already knows the answer to. And I set one rule early on: the agents only read online. Editing my Ancestry tree or uploading a file is my job.

It wasn’t perfect. Old German handwriting is still a weak spot: one automated transcription misread an Austrian marriage record badly enough to invent a surname, so we went with a German-speaking researcher’s reading over the AI translation.

How to try this yourself

If you already have a tree on Ancestry, FamilySearch, or another site, export it as a GEDCOM, put it in its own folder, run git init, and commit the original before anything touches it. If you’re starting from scratch, make the folder anyway and have the agent build a new GEDCOM from what you know: yourself, your parents and grandparents, any dates and places, and photos of documents like birth certificates or obituaries. Either way, a DNA test is worth it if you can, because the matches help a lot.

Then open the folder in Claude Code or Codex and start with something like this:

This folder holds my family tree as a GEDCOM. Read the README and the changelog first. When you research a person, cite the original record you read, say what it doesn’t prove, and mark anything that only rests on other people’s trees as provisional. Never record that something doesn’t exist without first running a search you know should succeed. When you find a story about someone’s life, add it to their record. Work on each research question in its own branch, and add a changelog entry explaining why for every change.

When it’s time to put the tree on Ancestry, upload one change at a time.

What I want next

I want the photos to travel with the tree, so a relative who opens it sees the 1912 adoption decree itself and not just a citation to it. The newest GEDCOM spec defines a zipped format, GEDZIP, that can bundle media files. I just need the sites I use to support it.

On the research side, I’m still in the process of providing direct evidence for generations 7 through 9. I also want the agents to read the Bohemian and Austrian registers directly, and see if 26 Mayflower passengers turns into 30. And if there’s a record out there that explains why Samuel Frye Chase III gave up his son, that’s the one I want most.

Three months ago, most of these people were just names and dates someone else had typed into a website. Now I feel like I actually know a few of them. And I’ve barely scratched the surface. There are still thousands of ancestors I haven’t found, and I’m sure more stories like these are sitting in an old register or newspaper somewhere. I’m excited to keep going.