<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: JacobRoberts</title>
    <description>The latest articles on DEV Community by JacobRoberts (@jrob1799).</description>
    <link>https://dev.to/jrob1799</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4211588%2F9caf36f5-563b-436f-928f-7d2168916911.jpg</url>
      <title>DEV Community: JacobRoberts</title>
      <link>https://dev.to/jrob1799</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jrob1799"/>
    <language>en</language>
    <item>
      <title>hauntctl: I Held a Séance for My Git History</title>
      <dc:creator>JacobRoberts</dc:creator>
      <pubDate>Tue, 27 Oct 2026 18:50:19 +0000</pubDate>
      <link>https://dev.to/jrob1799/hauntctl-i-held-a-seance-for-my-git-history-j1l</link>
      <guid>https://dev.to/jrob1799/hauntctl-i-held-a-seance-for-my-git-history-j1l</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;Repo: &lt;strong&gt;&lt;a href="https://github.com/Jrob1799/hauntctl" rel="noopener noreferrer"&gt;https://github.com/Jrob1799/hauntctl&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Commit: &lt;a href="https://github.com/Jrob1799/hauntctl/commit/a11ed941d80918b1b50dba3b053e63e1a898e7a9" rel="noopener noreferrer"&gt;&lt;code&gt;a11ed94&lt;/code&gt;&lt;/a&gt; on &lt;code&gt;main&lt;/code&gt;&lt;br&gt;&lt;br&gt;
License: MIT (code). Gemma weights stay under the &lt;a href="https://gemma.ai/resources/terms" rel="noopener noreferrer"&gt;Gemma Terms of Use&lt;/a&gt; and are not vendored in the repo.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;Three rites, one evidence packet:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it channels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hauntctl blame &amp;lt;file&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unexplained regions — old lines, &lt;code&gt;TODO&lt;/code&gt;/&lt;code&gt;HACK&lt;/code&gt;/&lt;code&gt;WIP&lt;/code&gt;, terse subjects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hauntctl seance&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An old commit (≥365 days before HEAD when possible), seeded so you can replay it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hauntctl ofrenda&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remembrance for a path deleted from HEAD (Día de los Muertos for dead code)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;If Gemma is not loaded, a deterministic &lt;strong&gt;spirit-board&lt;/strong&gt; fills the same packet and labels itself: &lt;code&gt;deterministic fallback · no model loaded&lt;/code&gt;. It will not dress a string fill-in as Gemma.&lt;/p&gt;
&lt;h2&gt;
  
  
  Theme: Ghost in the Machine
&lt;/h2&gt;

&lt;p&gt;I did not want jump-scare horror for its own sake. I wanted &lt;strong&gt;remembrance through blame&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;src/lantern.py&lt;/code&gt;, 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.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo (no model, no token, no network)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; hauntctl demo &lt;span class="nt"&gt;--into&lt;/span&gt; /tmp/forgotten-chapel &lt;span class="nt"&gt;--backend&lt;/span&gt; fallback &lt;span class="nt"&gt;--no-color&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Header from the expected session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spirit-board voice on blame (labeled fallback — not Gemma):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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.".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ofrenda for the longest-gone path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full transcript: &lt;code&gt;DEMO.md&lt;/code&gt; / &lt;code&gt;examples/sample-session.txt&lt;/code&gt; in the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo with Gemma 3 1B (local)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama serve
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; hauntctl summon          &lt;span class="c"&gt;# ollama pull gemma3:1b&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; hauntctl demo &lt;span class="nt"&gt;--into&lt;/span&gt; /tmp/forgotten-chapel-gemma &lt;span class="nt"&gt;--no-color&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git (read-only) → evidence packet → voice
                                 ├─ Ollama        gemma3:1b
                                 ├─ llama.cpp     local Gemma GGUF
                                 ├─ transformers  google/gemma-3-1b-it
                                 └─ spirit-board  deterministic template
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hauntctl&lt;/code&gt; never writes to the repository it reads. The git wrapper refuses &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;reset&lt;/code&gt;, &lt;code&gt;clean&lt;/code&gt;, and anything outside a short read allowlist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open innovation matters
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Running &lt;strong&gt;Gemma locally&lt;/strong&gt; is the better fit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The repository stays put.&lt;/strong&gt; In auto mode the evidence packet goes to &lt;code&gt;127.0.0.1&lt;/code&gt; (Ollama / llama.cpp) or an in-process transformers load. hauntctl does not phone home.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works with the network off&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No account and no per-token fee&lt;/strong&gt; for the basic demo or the Ollama path. Swap &lt;code&gt;gemma3:1b&lt;/code&gt; for another Gemma tag without rewriting the git half.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The fallback is honest.&lt;/strong&gt; When no model speaks, the tool says it used a template. It does not cosplay as Gemma.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Closed models are fine at sounding haunted. They are a poor place to store the memory of a private repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to run it in five minutes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Jrob1799/hauntctl &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;hauntctl
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; hauntctl demo &lt;span class="nt"&gt;--into&lt;/span&gt; /tmp/forgotten-chapel &lt;span class="nt"&gt;--backend&lt;/span&gt; fallback &lt;span class="nt"&gt;--no-color&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; hauntctl doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional: &lt;code&gt;pip install -e .&lt;/code&gt; from the repo root. Hear Gemma with &lt;code&gt;hauntctl summon&lt;/code&gt; after &lt;a href="https://ollama.com/download" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; is up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize categories
&lt;/h2&gt;

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

&lt;p&gt;Not entering Render, TabPFN, Tinker, Arduino, DigitalOcean, or other partner categories — the code does not use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built in the challenge window
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Challenge: &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Ghost in the Machine — Week 4&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/Jrob1799/hauntctl" rel="noopener noreferrer"&gt;https://github.com/Jrob1799/hauntctl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Commit: &lt;a href="https://github.com/Jrob1799/hauntctl/commit/a11ed941d80918b1b50dba3b053e63e1a898e7a9" rel="noopener noreferrer"&gt;&lt;code&gt;a11ed94&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;main&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Demo transcripts: &lt;code&gt;DEMO.md&lt;/code&gt;, &lt;code&gt;examples/sample-session.txt&lt;/code&gt;, &lt;code&gt;examples/sample-gemma-session.txt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;#devchallenge&lt;/code&gt; &lt;code&gt;#hf26challenge&lt;/code&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
