This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine

Every repo has a history that reads like a haunting once you look at it. The commits at 3 a.m. The three months of silence. The message that just says ugh. The last words before everyone left.

So I built Ghostwritten: paste your git log, and a local Gemma model tells you what haunts your repo, as a ghost story or as a eulogy.

A ghost story written from a git log

What I Built

Ghostwritten is a single web page with two moods, one for each half of the theme:

  • 👻 Ghost story. Eerie, with a dry sense of humour.
  • 🕯️ Eulogy. Warm and a little funny, in the spirit of Día de los Muertos: remembering with affection what a project was.

You run one command in a repo and paste the output. Next to the story you get The evidence: a list of clues counted by code, such as how many commits, the share made between midnight and 5 a.m., the longest silence, the busiest day, the commit messages that sound like cries for help, reverts, and contributors who went quiet.

It's for anyone who has ever scrolled git log and felt something.

Demo

Live: https://smaranikamondal.github.io/Ghostwritten/

Click Try a sample log to see it straight away. The hosted page can't run Gemma, so it uses a built-in template storyteller and says so under the story. With Ollama running locally, the same page uses your own Gemma. The README has the steps and a command for pulling your own repo's log.

The eulogy mode

(Both screenshots use the built-in sample log, a made-up repo called sample-app)

Code

👻 Ghostwritten

Paste your git log. A local Gemma tells you what haunts your repo.

A ghost story, or a eulogy, written from the facts of your commit history. Everything runs on your own machine.

HTML deps model Hacktoberfest

Ghostwritten ghost story

Why this exists

Every repo has a history that reads like a haunting once you look at it: the commits at 3 a.m., the months of silence, the message that just says ugh, the last words before everyone left. Ghostwritten finds those clues and turns them into a short story.

It has two moods, for the two halves of the Ghost in the Machine theme:

  • Ghost story: eerie, with a dry sense of humour.
  • Eulogy: warm and a little funny, in the spirit of Día de los Muertos: remembering with affection what a project was.

Built for the Hacktoberfest Open-Source AI Challenge, Week 4: Ghost in the Machine (Oct 26-31, 2026). Started and finished…

How I Built It

One HTML file, no framework, no build step, no dependencies. The model is Gemma, served locally by Ollama.

1. Code counts the facts. The model only narrates. Counts, percentages, gaps, and dates are all computed in plain JavaScript. The "after midnight" hour comes from each commit's own recorded timestamp, not the browser's time zone. The evidence list is shown beside the story, so you can see what the story is built from.

2. The model gets the evidence as data. The evidence is wrapped in tags, and the prompt tells Gemma to ignore any instructions inside it, which matters because commit messages are untrusted text. It also tells the model to use only numbers and dates from the evidence, and to copy any commit message it quotes exactly.

3. Then code checks the story. Models invent things, so every sentence is checked:

  • Any quoted text must appear in your real commit messages. Quote marks are paired in order, so "wip" and "ugh" are checked as two quotes.
  • Any number must appear in the evidence. Times like "3 a.m." and ordinals are allowed.
  • A sentence that talks about "the evidence" is dropped.

Offending sentences are removed, and the page says how many. If too little is left, it retries once at a lower temperature. If that fails, or there's no model, it falls back.

4. A built-in storyteller means the page always works. With no Ollama, a template storyteller writes a ghost story or eulogy from the same evidence, with a few variants chosen from the data. That's what makes the hosted demo real, and the byline always says which one wrote the story.

5. Names are off by default. Contributor names are never shown or sent to the model unless you tick a box. A ghost story is a joke about a repo, and I didn't want to make it a joke about a person.

6. Everything the model writes is shown as plain text, never as HTML.

7. Tests. I tested it in a headless browser against a mocked Ollama. The evidence maths is compared with an independent Python implementation run on the same data, and the checks also cover the guard, retries, the fallback, both log formats, junk lines, a 600-line log, HTML injection, reduced motion, and the phone layout. All 60 checks pass. That tests the app's logic, not Gemma's prose, which depends on the model you run.

Honest limits.

  • The guard is narrow. It catches invented digits and invented quotes, but spelled-out numbers and made-up file names or events can slip through. The story is fiction narrated from facts, so read it as fiction.
  • Small models vary. That's why there's a retry and a fallback. A larger Gemma may do better, but I haven't tested that.
  • "Cries for help" is a keyword match on words like wip, ugh and why. It's a joke detector, not sentiment analysis.
  • Plain --oneline output has no dates, so there are fewer clues.
  • Please don't use ghost stories to judge real people.

Why Does Open Innovation Matter?

Commit history is private: internal project names, unreleased features, and the messages you'd never show a client. Here is where an open approach worked better than a hosted one:

  1. The history never leaves your machine. There's no server in the loop, so a work repo is as safe to paste as a hobby one.
  2. Retries are free. The guard throws away drafts and asks again. With a metered API, that checking loop would cost money on every story. Locally, it's just a few seconds.
  3. It works offline, and the model can't change behaviour underneath you.
  4. Swapping models is one dropdown. The list comes from whatever Ollama has installed.

Prize Categories

  • Best Use of Gemma. Gemma writes the ghost stories and eulogies locally through Ollama. The app detects and selects it automatically, keeps its job to narration, and checks everything it returns.

Built with AI coding assistance. Gemma is provided under and subject to the Gemma Terms of Use found at ai.google.dev/gemma/terms.