Every repo has ghosts

Bhoot reads a repository's git history and finds the people who left but whose code still runs, plus every file that died. A local Gemma writes each one a short remembrance. Git checks every word before it goes on the stone.

Express81%of the code that runs today was written by its 12 ghosts
Git545files died in Express's history
★ Held out3/3made-up details caught on a repo the checker never saw

Ghosts found in Express

TJ DW RS WT +8

What it finds

In Hindi, bhoot means ghost. It also means the past.

Old repositories are full of both. Bhoot looks for two kinds.

Ghosts

People who haven't committed in a year or more, ranked by how many of their lines git blame still finds. TJ Holowaychuk last committed to Express in February 2014. 6,483 of his lines still run.

Graves

Every deleted file gets a tombstone with its birth, its death and the people at both ends. The cause of death is the commit that removed it. Express's original docs went in April 2012, 31 files in one commit called "removed old docs".

The checker

Gemma is good at tone. It is bad at counting.

TJ's spirit persists, 3,527 silent years woven into 6,483 lines of code.
✕ rejected Gemma's first try. 3,527 is real. It's his commit count.

Most of Gemma's mistakes looked like this one, a true number pinned to the wrong noun. 32 commits became "32 contributors". 9 commits became "nine brief lives". A checker that only asks whether a number appears in the facts lets every one of them through, so this one reads what each number counts.

1

Numbers count the right thing

6,483 lines passes. 3,527 years fails.

2

Years match the right event

"Born in 2012" has to be the year the file was born.

3

Names match the right role

"Removed by Sebastian" has to match the commit that deleted it.

4

The rest comes from git

Months, quotes, file names, and any word that looks like a name.

A remembrance that fails gets one retry, and Gemma is told what it got wrong. If it fails twice, the stone carries plain dates. Every stone has a badge that says which happened.

How it works

Three steps, all on your laptop

01 · git

Read the history

log, blame, and every file a commit deleted. "TJ Holowaychuk", "Tj Holowaychuk" and "visionmedia" become one person.

02 · gemma

Write two sentences

Gemma 3 4B in Ollama, on the same machine. Warm, a little eerie, never mocking.

03 · checker

Check every claim

Every number, year, name and file is matched against git before the stone is carved.

Numbers

How often Gemma got it wrong

I labelled every first attempt by hand. Then I froze the checker in a commit and ran a repo it had never seen.

Express + request
22/78of Gemma's first tries were false
22/22caught
0/56true ones rejected
★ underscore, held out
3/16of Gemma's first tries were false
3/3caught
1/13true ones rejected, by an apostrophe bug I fixed after

I tuned the checker on Express and request, so those numbers flatter it. Underscore is the honest test, and sixteen stones is small. The labels, every attempt Gemma made and the scoring script are in the repo, so you can disagree with me line by line.

Walk a graveyard

Three repos, already read

Why it runs locally

A git history is personal

It stays on your laptop

Who stayed late, who left, whose code got rewritten. Git reads it locally and Gemma runs in Ollama, so none of it goes to a model service.

Same repo, same stones

The seed is fixed. When I changed the checker, I re-ran it on the exact attempts Gemma had already written and measured the difference.

Remembering is free

Express has 387 people in its history. Writing to every one of them costs an evening of laptop fan, not a bill.

Run it

Raise your own graveyard

Node 22.18 or newer and Ollama. No dependencies and no build step.

# once
ollama pull gemma3:4b
git clone https://github.com/codeswithroh/bhoot && cd bhoot

# any repo you have locally
node src/cli.ts /path/to/your/repo --out graveyard
open graveyard/index.html

Questions

Before you raise the dead

Does my code leave my machine?

No. Git reads the history, Gemma runs in Ollama on the same machine, and the output is one HTML file. There's no account and no API key.

Who counts as a ghost?

Anyone who hasn't committed for at least a year before the repo's latest commit and still has at least 50 lines at HEAD. Both numbers are flags. Lockfiles, build output and binaries don't count.

Isn't calling people ghosts a bit rude?

People leave projects for good reasons. The prompt says "never mocking", and the page is built around Día de los Muertos, which is about remembering people by name with the details right. It reads more like a thank-you note.

Why Gemma 3 4B?

It runs on an 8 GB laptop. A bigger Gemma is one environment variable away, and the checker stays the same. A better model makes fewer mistakes. The checker catches the ones it still makes.

What can't the checker catch?

It checks facts, not judgement. It knows whether "born in 2011" is true. It can't tell you whether "a quiet guardian" is fair.

Go meet the people still running your code

Open the graveyard