This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
What I Built
I gave an AI eight facts about a grandmother and asked for a short remembrance. It gave her a smile that wasn't in the facts.
That is why I built honest-ofrenda. You type 6 to 8 facts about someone you remember for your ofrenda: their name, a year, a favourite food, a story. An open-weight model (Qwen3-8B) turns them into a few warm sentences. Then plain Python code checks what the model wrote against your facts and shows you everything it added.
For the theme, the ghost in this machine is what a language model does without being asked: it adds details. A smile. A candle. A prayer. In a remembrance for someone who has died, those invented details are the haunting. So I didn't try to hide the ghost. I built a tool that makes it show itself.
I took the DÃa de los Muertos side of the theme: honoring the past, not the spooky side. It is for anyone who wants help with the words but doesn't want an AI inventing memories. Both people in this post, Sunanda Kulkarni and Ramesh Joshi, are made up. I have not run it on a real family's facts.
Demo
There is no live demo. It runs on my own laptop, and any public version would send visitors' text to a hosted API. Here is a real run on the made-up grandfather:
I remember Ajoba teaching me how to whistle while fixing bikes.
He kept a blue notebook with train times for 120 routes.
He loved shrikhand and would eat it every Sunday.
...
Checker: FLAGGED
- name: Sunday
Review by hand (soft claims not in your facts): every
His facts say he whistled while repairing bicycles, kept a notebook with 120 train times, and that shrikhand was his favourite food. The model turned that into teaching me to whistle, 120 routes, and a Sunday ritual nobody mentioned.
Runs took between 38 and 46 seconds each. They were single runs, and the first included a cold start, so please don't read them as benchmarks.
Code
honest-ofrenda
What it is
honest-ofrenda is a tool that turns biographical facts about a remembered person into a short remembrance for an ofrenda. The open-weight language model writes the wording, while deterministic code checks that the draft introduces no names or numbers absent from the provided facts.
Run it
Install dependencies:
pip install -r requirements.txt
Set your Tinker key in .env:
API_KEY=your_api_key_here
MODEL=Qwen/Qwen3-8B
Run the tool:
python -m ofrenda.cli samples/sunanda.txt --save out/sunanda.md
Use it for someone you remember
Copy samples/template.txt into a folder named my_facts/ (which is git-ignored), and fill in 6 to 8 facts about the person.
Run the tool:
python -m ofrenda.cli my_facts/yourfile.txt --save out/yourfile.md
Read every sentence yourself, and compare it with your facts because the checks catch only some changes. Note that your facts are sent to the Tinker hosted API. The tool has been run only on the two made-up samples, not on a…
MIT licence. 42 tests pass, and none of them call the model.
pip install -r requirements.txt
# put your Tinker key in a .env file (API_KEY=...)
python -m ofrenda.cli samples/sunanda.txt --save out/sunanda.md
There is also a blank samples/template.txt for using it on someone you remember, and a README section on how.
How I Built It
My rule was: the model proposes, plain code checks.
- The model (Qwen3-8B on Tinker, thinking turned off) writes 4 to 6 sentences from your facts only. The prompt tells it not to add names, numbers, places, foods or songs, and not to describe feelings or looks unless a fact says so.
- A checker compares every number and every capitalised word with your facts. A made-up year, price or name gets flagged.
- A soft-word list flags words like always, every, smile and warmth when they aren't in your facts.
- An evidence view shows, for each sentence, the closest fact and the words that appear in no fact. It has false alarms ("selling" vs "sold"), so it's a review aid, not proof.
-
A local web page.
python serve.pyopens a small page on your own computer, with no live demo. It asks for at least 4 facts besides the Name line and shows the same checks.
What went wrong
-
A leaked token. The first output ended with
<|im_end|>, the model's own end marker. I added a cleaner. - A smile the checker couldn't see. The first run ended with "the way she smiled and the warmth she brought". The checker said nothing unsupported, because that line has no name or number. That is why the soft-word list and the evidence view exist.
- 7 of 12 sentences drifted. I read the two saved pages against the facts by hand. "Teaching me how to whistle", "120 routes", "every Sunday", "for the first time", "with care and pride", "loved making puran poli" and "a quiet presence, steady and strong" are all additions or changes. The checker and soft-word list flagged 2 of those 7 sentences. The evidence view listed unmatched words in all 7. This is my own hand count of 12 sentences, not a benchmark.
- One fact is a trap. In the browser I once gave it a single fact. The model wrote six sentences of invented ritual: candle, marigolds, photo, water bowl, altar, prayer. The checker said nothing unsupported. The evidence view marked 5 of the 6 sentences as matching no fact. That is why the page now requires at least 4 facts.
- The smile came back. Running the made-up grandmother again in the browser, the model wrote "She always had a smile on her face". This time the soft-word list caught always and smile, but it still missed "She loved making puran poli" (her favourite food, not her hobby).
What I did not do
- No real person's facts, and no first user yet.
- No fine-tuning, no local model and no comparison with a closed model.
- No test with facts that contain instructions.
- No live demo. The web page runs only on my laptop.
Why Does Open Innovation Matter?
I'll be careful here. This does not run offline, and your facts are not kept on your machine. Qwen3-8B runs on Tinker's hosted API, because my 4 GB laptop can't run an 8B model. Your facts are sent to that service, and the README says not to use it for anything you wouldn't send to a hosted service.
What the open pieces gave me:
- A model I can name and swap. Which model writes the text is one line in a settings file. I did not test another model, so that is a design point, not a result.
- A checker that doesn't depend on the model. It is plain Python, so it behaves the same whichever model writes the text. That matters most here, because the model is the part I can't trust.
- Weights anyone can download. Someone with a bigger machine could run the same model at home. I haven't tried that.
- Code you can read and fork. MIT licence, and the whole pipeline fits in a few small files. The model call still depends on Tinker, so if that host went away you'd need to point it at another one.
I didn't compare this with a closed model, so I can't say the open one did better. I can only say what it did: it made up details, and the code around it caught some of them.
My Agent Session
I wrote the code with Google's Antigravity (Gemini) and planned each step with Claude. I checked every report against the raw output, because the agent overstated things. Twice it also broke my rules. It opened its own log files outside the project folder. And when my safety scan flagged a harmless pattern in the error-cleaning code, it split the string in two so the scanner would stop seeing it. That is a funny thing to catch in a project about not letting a machine quietly change the facts. I left it in and I don't call it a security feature. No saved session link.
The Spirit of It
The moment it landed was small. Across my runs on the made-up grandmother, the model kept reaching for the same kind of ending: a smile, warmth, "a quiet presence, steady and strong". Nice words, generic, and nobody gave them to it.
A real remembrance is made of specific things: 5 marigold plants on a balcony, 6 kilometres walked to see a first film, a favourite food. Those came from the facts. The additions were the vague ones. I'd rather have the five plants.
I haven't shown it to anyone yet, and this post won't pretend I have. The tool's job is to help a person write what they remember, and then to point at everything that wasn't theirs.
Prize Categories
Entered in the overall Week 4 challenge, on the DÃa de los Muertos side of the theme. No partner category. Tinker's category needs a fine-tune with a measured improvement over a baseline, and I only used inference, so I didn't enter it.
Top comments (0)