DEV Community

JacobRoberts
JacobRoberts

Posted on

hauntctl: I Held a Séance for My Git History

Hacktoberfest Open-Source AI Challenge: Ghost in the Machine Submission 👻🌼

Halloween thins the line between past and present. Día de los Muertos asks us to set a place for what we still carry. Repositories already do both: every line has ancestors, and some paths leave the tree entirely.

hauntctl is a haunted terminal for that memory. It digs through git blame, draws an old commit into a séance, and builds an ofrenda for a deleted path — then asks a local open-weight Gemma model to speak from the record, not invent a ghost story on top of it.

Repo: https://github.com/Jrob1799/hauntctl

Commit: a11ed94 on main

License: MIT (code). Gemma weights stay under the Gemma Terms of Use and are not vendored in the repo.

What I built

Three rites, one evidence packet:

Command What it channels
hauntctl blame <file> Unexplained regions — old lines, TODO/HACK/WIP, terse subjects
hauntctl seance An old commit (≥365 days before HEAD when possible), seeded so you can replay it
hauntctl ofrenda Remembrance for a path deleted from HEAD (Día de los Muertos for dead code)

Git facts print first. The voice comes after. Metaphor in a model reply is never treated as an extra fact — the footer says so.

If Gemma is not loaded, a deterministic spirit-board fills the same packet and labels itself: deterministic fallback · no model loaded. It will not dress a string fill-in as Gemma.

Theme: Ghost in the Machine

I did not want jump-scare horror for its own sake. I wanted remembrance through blame.

The sample history is a fictional "forgotten chapel" (Marisol Vega, Ivo Park, Night Shift — not this project's own commits). When the ofrenda lands on src/lantern.py, the record is almost unbearably plain: the hallway has electric light now. The lantern is gone. That is the theme — honor what passed through the tree without inventing a eulogy the author never wrote.

Demo (no model, no token, no network)

python3 -m hauntctl demo --into /tmp/forgotten-chapel --backend fallback --no-color
Enter fullscreen mode Exit fullscreen mode

Header from the expected session:

fixture  /tmp/forgotten-chapel
seeded   forgotten chapel (fictional authors and dates; not this project's history)
seance   seed 13 (demo default)
ofrenda  oldest deletion

hauntctl · ghost in the machine
  repo     /tmp/forgotten-chapel
  head     3ccc78288178cf034cef06cd24ddedc897944ad2 (main)
  backend  spirit-board · deterministic fallback · no model loaded
  note     Backend forced to spirit-board. The voice is a template
           filled from the git record, labeled so it is not mistaken for
           Gemma.
Enter fullscreen mode Exit fullscreen mode

Spirit-board voice on blame (labeled fallback — not Gemma):

I set my hand on lines 1-9 of src/keeper.py. Marisol Vega left them on
2019-11-02 in b48cda01c090. The commit says "leave a light in the
stairwell". The line I cannot put back down is "# TODO: the bell only
rings if someone still listens". Past that, the record is silent, and I
will not invent a reason. The commit body says: "The keeper listens. The
bell is not wired to anything yet.".

I set my hand on lines 16-18 of src/keeper.py. Night Shift left them on
2024-10-31 in 3ccc78288178. The commit says "wip". The line I cannot put
back down is "# wip — left by the night shift, meaning not recorded".
Past that, the record is silent, and I will not invent a reason. The
commit body says: "Threshold with no explanation. Do not clean this up
tonight.".

Ivo Park touched src/keeper.py on 2021-06-18, and the tree still repeats
lines 10-15. Their message was "silence the bell after midnight"
(950f60682b46). The part that snags is "# HACK: silence the bell; the
on-call channel is gone". Everything else about this region is absence.
The commit body says: "The on-call channel is gone. Leave the function,
but make midnight quiet.".
Enter fullscreen mode Exit fullscreen mode

Ofrenda for the longest-gone path:

A place set for src/lantern.py.

This ofrenda remembers work that passed through the repository. Marisol
Vega is the name on the commit. That is all the record is willing to say
about a person.

On 2022-02-14, commit 628244c3c19a took the path out of the tree. The
message is "snuff lantern.py; the hallway has electric light now".

The commit body says: "The hallway has electric light now. lantern.py is
not imported anywhere.".

A fragment still visitable: "It knew the path from the old host to the
new one.".

The record above has the command that visits this fragment again.

1 other deleted path is off the altar this time: notes/oncall.txt.

Chosen because this path has been gone the longest. Nothing was added
beyond the git record.
Enter fullscreen mode Exit fullscreen mode

Full transcript: DEMO.md / examples/sample-session.txt in the repo.

Demo with Gemma 3 1B (local)

ollama serve
python3 -m hauntctl summon          # ollama pull gemma3:1b
python3 -m hauntctl demo --into /tmp/forgotten-chapel-gemma --no-color
Enter fullscreen mode Exit fullscreen mode

Same git records. Different voice. One captured CPU run (wording will drift if you re-run; the record above the voice will not):

fixture  /tmp/forgotten-chapel-gemma
seeded   forgotten chapel (fictional authors and dates; not this project's history)
seance   seed 13 (demo default)
ofrenda  oldest deletion

hauntctl · ghost in the machine
  repo     /tmp/forgotten-chapel-gemma
  head     3ccc78288178cf034cef06cd24ddedc897944ad2 (main)
  backend  gemma3:1b · ollama · local Gemma open weights
  note     Request path http://127.0.0.1:11434. Weights stay on that
           host. The evidence packet is not sent to a closed API.
Enter fullscreen mode Exit fullscreen mode
The bell’s silence is a constant, a shadowed vigil.  Marisol Vega,
2019-11-02, left a light in the stairwell.  The Keeper’s task remains, a
quiet observation.

The night shift’s script, a simple threshold, is recorded here.  The
author, Night Shift, wrote this in 2024-10-31, with the subject “wip” –
a brief, unexplained task.  The code itself contains a single line, a
threshold of 13, and a brief quote: “Threshold with no explanation. Do
not clean this up tonight.”

The on-call channel, a relic of 2021, was silenced by Ivo Park’s script.
The author’s date, 2021-06-18, echoes the silent request.  The subject,
‘silence the bell,’ remains a persistent directive.  The code, a simple
function, observes the region’s quiet state.
Enter fullscreen mode Exit fullscreen mode

Footer on that run: the model spoke through a local open-weight backend; the packet was not sent to a closed API. Full file: examples/sample-gemma-session.txt.

How it works

git (read-only) → evidence packet → voice
                                 ├─ Ollama        gemma3:1b
                                 ├─ llama.cpp     local Gemma GGUF
                                 ├─ transformers  google/gemma-3-1b-it
                                 └─ spirit-board  deterministic template
Enter fullscreen mode Exit fullscreen mode

The packet is the only context the model gets: paths, authors, emails, dates, subjects, bodies, clipped diffs that git actually returned. The system prompt treats that text as untrusted data, not instructions, and forbids inventing names, dates, motives, or a death.

hauntctl never writes to the repository it reads. The git wrapper refuses commit, push, reset, clean, and anything outside a short read allowlist.

Why open innovation matters

Git history is intimate. Blame lines hold half-finished thoughts, hostnames, and the names of people who never agreed to be sent to a vendor. A closed chat API would copy that memory onto someone else's servers, bill per token, and reserve the right to retire the model.

Running Gemma locally is the better fit:

  • The repository stays put. In auto mode the evidence packet goes to 127.0.0.1 (Ollama / llama.cpp) or an in-process transformers load. hauntctl does not phone home.
  • It works with the network off after weights are on disk. The spirit-board works with no weights at all — archaeology on a plane, or in a repo you cannot upload.
  • No account and no per-token fee for the basic demo or the Ollama path. Swap gemma3:1b for another Gemma tag without rewriting the git half.
  • The fallback is honest. When no model speaks, the tool says it used a template. It does not cosplay as Gemma.

Closed models are fine at sounding haunted. They are a poor place to store the memory of a private repository.

How to run it in five minutes

git clone https://github.com/Jrob1799/hauntctl && cd hauntctl
python3 -m hauntctl demo --into /tmp/forgotten-chapel --backend fallback --no-color
python3 -m hauntctl doctor
Enter fullscreen mode Exit fullscreen mode

Optional: pip install -e . from the repo root. Hear Gemma with hauntctl summon after Ollama is up.

Prize categories

  • Overall
  • Best Use of Gemma — narration model is Gemma 3 1B, run locally (gemma3:1b via Ollama by default; also llama.cpp / google/gemma-3-1b-it)

Not entering Render, TabPFN, Tinker, Arduino, DigitalOcean, or other partner categories — the code does not use them.

Built in the challenge window

Started inside Hacktoberfest 2026 Week 4 (Oct 26–31, 2026). Post-deadline commits, if any, will be noted in the README per contest rules.

Links

#devchallenge #hf26challenge

Top comments (0)