This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
What I Built
Every git repository is a graveyard, and nobody holds the ceremony.
Somewhere in your history there's a pricing.html that shipped before the
product existed, an app_v2.py from the rewrite that never finished, a
stylesheet in hotpink you were proud of for six hours. git log will tell
you when they died. It will never tell you what they meant — so they rot,
unmourned, while you scroll past their filenames looking for something else.
ofrenda is the ceremony. It's a Día de los Muertos altar for your code:
$ ofrenda examples/graveyard-repo
ofrenda :: 4 departed :: model gemma3:4b
[1/4] app_v2.py
“Served 'eventually'. Rest now.”
[2/4] index.html
“A valiant start, now dust.”
[3/4] pricing.html
“A valiant, if misguided, attempt.”
4 remembered, 0 unspoken
ofrenda lit → …/ofrenda.html
The tool walks your history for every deleted file and digs up its whole
life: the commit that created it, the people who touched it, how many
commits it survived — and, on the eve of its death, the literal content it
was still carrying. Then it hands that record to a model running on your
own machine and asks it to say a few words. What comes back is one
self-contained HTML page: papel picado across the top, a candle-lit
gravestone per file, each with an epitaph, a short story, a cause of death,
and the things it was beloved for.
I interpreted "Ghost in the Machine" this way: the ghosts aren't monsters,
they're the dead we didn't memorialize, and the machine finally gets to
speak for them. Halloween gives you the graveyard; Día de los Muertos tells
you what to do there — remember deliberately, warmly, and with candles.
Who this is for: anyone who has ever rewritten a project "from scratch" and
later wondered what the old version actually did; maintainers doing cleanups
who want a moment of gratitude before the rm; teams onboarding someone who
needs to understand not just what exists, but what was tried and abandoned.
Demo
No deployment needed — it's your own machine, and the page it prints is a
single file you can open with the Wi-Fi off.
git clone https://github.com/itzneel05/ofrenda && cd ofrenda
ollama pull gemma3:4b
pip install -e .
python examples/make_demo_repo.py # grows a small graveyard to mourn
ofrenda examples/graveyard-repo # writes ofrenda.html
Real captured output — four dead files, four eulogies, straight from
gemma3:4b:
ofrenda :: 4 departed :: model gemma3:4b
[1/4] app_v2.py
“Served 'eventually'. Rest now.”
[2/4] index.html
“A valiant start, now dust.”
[3/4] style.css
“A vibrant blush, now gone.”
[4/4] pricing.html
“A valiant, if misguided, attempt.”
4 remembered, 0 unspoken
ofrenda lit → C:\...\ofrenda.html
And what the model wrote for pricing.html, verbatim from --json:
{
"path": "pricing.html",
"epitaph": "A valiant, if misguided, attempt.",
"story": "Launched with a bold promise of zero cost, pricing.html bravely represented the nascent product — a testament to early enthusiasm and, frankly, a bit of optimism. Its short existence ended abruptly when the Demo Author deemed its message 'sad'.",
"cause_of_death": "deleted",
"beloved": ["Zero cost", "Early optimism", "A brief, memorable moment"]
}
Every claim in that story is grounded in evidence the tool actually fed it:
the file's content (<h1>Only $0 — because nothing works yet</h1>), the
commit that killed it (fix: pricing page was making everyone sad), and
its two-commit lifespan.
Other flags: --limit 10 (ten newest deaths), --model gemma3:1b
(smaller machines), --json (for scripting), --out altar.html.
Code
https://github.com/itzneel05/ofrenda
-
ofrenda/gitdead.py— the archaeology:git log --diff-filter=Dfor deaths,--followfor birth/lifespan/contributors,git show <death>^:<path>for the content at death. Parses git's raw record separators byte-carefully (a fun bug: Python'ssplitlines()treats\x1eas a line break, which silently swallowed every finding until a test caught it). -
ofrenda/eulogy.py— prompt built from the evidence, plus a tolerant JSON parser for whatever the model decides to wrap it in (fences, chatty prefixes, trailing "Hope that helps!"). -
ofrenda/client.py— stdlib Ollama client. No base-URL flag, no API key:127.0.0.1:11434and nowhere else. -
ofrenda/render.py— the altar itself: one HTML file, zero scripts, zero CDNs, everything escaped. -
tests/— 24 tests, none of which need a model: they build real temporary git repos (commits, deletions, renames), dig through them, and assert the page escapes hostile output and makes zero external requests.
flowchart TD
A["git log --diff-filter=D<br/>which files died, and who killed them"] --> C["life record per file"]
B["git log --follow + git show death^:path<br/>birth, lifespan, contributors, final content"] --> C
C --> D["prompt built from the evidence"]
D --> E["gemma3:4b on 127.0.0.1:11434<br/>(local, via Ollama)"]
E --> F["epitaph · story · cause of death · beloved[]"]
F --> G["HTML-escaped into one self-contained<br/>candle-lit ofrenda page"]
Zero runtime dependencies. Python 3.9+, git, Ollama, done.
How I Built It
Built with AI assistance in OpenCode, with Google's open-weight Gemma 3 running locally through Ollama.
Why Does Open Innovation Matter?
Because the code that gets deleted is often the code you'd least want to
upload. Personal projects with your real name in the history. A client's
proprietary logic you still have an NDA about. The half-finished side
business. A repository that contains a layoff's worth of commit messages.
Asking a cloud API to read every deleted file in your history — and write
about your team while it's at it — is a question you'd never get a yes to,
which is exactly why the tool would be useless if it asked.
With an open-weight model on localhost:
- Nothing leaves the machine. The only socket involved is loopback; there is no code path to an external host. The demo above ran on a laptop with no internet.
- It costs nothing per candle. Forty deleted files, forty eulogies, zero dollars — so you'll actually run it on your real repositories instead of saving it for a special occasion.
- It works on a plane, or behind a corporate firewall where "we sent your git history to a third party" is a career-limiting sentence.
-
You can swap the voice.
--model gemma3:1bfor speed, fine-tune Gemma on your team's commit-message humor and the eulogies start sounding like your dead codebase actually did. A closed API is one pricing change away from never writing another word.
The Spirit of It
I didn't expect this part to land. The demo repo is synthetic — six commits
I wrote ten minutes earlier — and the model still produced, for a
two-line file named app_v2.py that returned the string 'eventually':
"Served 'eventually'. Rest now."
That's a two-line function getting a headstone. I ran it again and got a
different epitaph, same feeling. The point of Día de los Muertos was never
accuracy about the dead — it was the remembering. A tool that makes you stop
and read what your cleanup commit actually destroyed, for eight seconds
per file, on your own machine, is a small machine for exactly that.
Prize Categories
-
Best Use of Gemma —
gemma3:4b(andgemma3:1b) via Ollama is the sole author: every epitaph, story, cause of death and beloved-trait list comes from the model. There is deliberately no template fallback — if the model is missing, the tool stops, because a mad-libs condolence would miss the entire point.
Top comments (0)