DEV Community

Toheeb Olanrewaju Olagoke
Toheeb Olanrewaju Olagoke

Posted on Edited on

I let three ghosts into my terminal. One of them remembered what I was doing three months ago tonight.

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

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

What I Built

Haunted Shell is A Christmas Carol for your terminal.

In Dickens, three spirits visit Scrooge in one night: the Past, the Present and the Yet to Come. In Haunted Shell they visit your shell, and everything they know comes from your own machine: your git history, your shell history, the repo you're standing in. All of it is read and narrated by an open-weight model running on my laptop, with the Wi-Fi off.

☾ The Ghost of Commits Past walks through every git repository on your computer and finds what you were doing on this same day in earlier months and years. It shows you the real commits first, then takes you by the hand.

▌ The Ghost of Commits Present is Mortimer, a Unix sysadmin who died in 1987 in a freezing server room while a tape backup was running. He lives under your prompt and whispers about the commands you run. Fail a command, force-push, rm -rf something, or type gti status at 2 a.m., and he has something to say.

⧗ The Ghost of Commits Yet to Come never jokes. Run it inside a project and it points at what you've been neglecting: the oldest TODOs (dated with git blame), forgotten stashes, uncommitted files, dead branches. Then it prophesies, and ends the way Dickens did.

haunt carol brings all three, one after another. With haunt voice on, they whisper out loud.

How I read the theme: Halloween is about ghosts. Día de los Muertos is about remembering. The most honest ghost living inside my machine turned out to be me: months of commit messages written at one in the morning that I had completely forgotten. Haunted Shell lets that ghost speak.

The moment it landed

The first time I ran haunt past for real, this is what came back:

☾  The Ghost of Commits Past
   Here is what you were doing on the 30th of earlier months:

  30 Jul 2026  01:03  undertone         Add submission Q&A
  30 Jul 2026  01:03  undertone         Add submission copy
  30 Jul 2026  01:05  undertone         Add contribution description
  30 Jul 2026  18:33  awesome-phone-ca  feat: add pharmacy-stock-check skill
  30 Jul 2026  22:02  rxfind            RxFind: pharmacy stock check agent on CALL-E
  30 Jul 2026  23:27  rxfind            fix: handle semicolon field separator in summary parsing

☾ I take your hand, and we step into the shadows of yesterday's code.
  Three months ago, on Thursday 30 July 2026 at 01:03, you sat before a
  computer screen with the message "Add submission Q&A" etched in its
  digital heart. At 01:05, just two minutes later, your fingers danced
  across the keyboard again, this time with the words "Add contribution
  description". Later that evening, as night descended, at 18:33, you
  conjured a new feature for awesome-phone-call-agents.
Enter fullscreen mode Exit fullscreen mode

Three months ago tonight, at one in the morning, I was finishing the submission for Undertone. Undertone measures the colour of your skin, hair and eyes, works out which seasonal palette you belong to, scores a garment catalogue against that palette with a perceptual colour-difference metric, and then shows you the best matches on your own photo.

By that evening I had moved on to RxFind, a pharmacy stock-check agent on CALL-E. It came from a problem everyone has had: you need a specific medication today. Which pharmacy actually has it, at what price, and will they hold it for you? The only way to find out is to call them one at a time and ask the same four questions. At 23:27 I was still fixing its parser.

When the ghost brought that night back, my first reaction was: wow. I couldn't believe it. I had to go and check my git log to believe it, and every line was real. I was shocked, and it was amazing. A ghost I built had brought back the night I shipped Undertone, while I was writing the post for this one.

Meet the spirits

▌ The Ghost of Commits Present

Mortimer is a little too observant. These are real whispers from the day I set the project up and pushed it to GitHub:

$ git remote add origin https://github.com/Olacode01/haunted-shell.git
▌ Your little joke about the Dickens classic won't fetch any applause,
  I'm afraid. The GitHub world is all code now; what'll be next,
  a git pull of existential dread?

$ git commit -m "Keep post draft local"
▌ They forgot the `git push` part, didn't they? The remote's still
  holding onto that draft, a spectral reminder of their oversight...

$ ls~ls
zsh: command not found: ls~ls
▌ Your haste has brought forth the specter of syntax errors. Did you
  mean to summon 'grep', or was it a desperate cry for help?
Enter fullscreen mode Exit fullscreen mode

He was right about the git push. I ran it next.

haunt present also gives you a review of your day so far. Here is his summary after I'd spent half an hour hunting for a folder:

▌  The Ghost of Commits Present (Mortimer)
  • They have been at the terminal since 10:28 today, about 27 minutes, and have run 18 commands.
  • 4 commands failed. The last one to fail was: find ~ -maxdepth 4 -type d -name rxfind 2>/dev/null
  • They keep running the same command: cd ~/Downloads/haunted-shell (4 times).

▌ You've been staring at this screen for nearly half an hour now, 27 minutes
  of futile typing. Four commands have withered away in the darkness, one of
  them a desperate search for something called 'rxfind'. You keep returning
  to that haunted-shell folder, four times already, but it remains empty
  and unforgiving.
Enter fullscreen mode Exit fullscreen mode

⧗ The Ghost of Commits Yet to Come

Pointed at RxFind, the hooded spirit found a file I'd left uncommitted for a month and a half:

⧗  The Ghost of Commits Yet to Come
   It raises one finger toward rxfind:

  † The last commit was 46 days ago: fix: recover fields from prose summaries; document the unstable format
  † 2 uncommitted changes sit in the working tree; the oldest, server.py, has waited 46 days without being committed

⧗ The unrecovered fields will be lost forever. The field descriptions will no
  longer accurately reflect the data. Server.py will remain unchanged and its
  functionality unsaved. These are shadows of what may be. You could commit
  those changes today.
Enter fullscreen mode Exit fullscreen mode

How I Built It

https://github.com/Olacode01/haunted-shell

The whole thing is one Python file using only the standard library (it runs on the python3 that ships with macOS), a 30-line zsh plugin, and an Ollama Modelfile. No pip installs, no server, no framework. The model is Llama 3.2 3B, running locally through Ollama.

The Ghost of Commits Present uses zsh preexec/precmd hooks to catch each command and its exit code. Before calling the model, haunt checks for omens (rm -rf, force-pushes, exit 127, Ctrl-C, running the same command twice, the witching hour) and writes them into the prompt in plain English, like "they force-pushed, rewriting history that others may have seen". That makes a 3B model far more specific than just showing it a raw command. Replies stream from Ollama's local API and type themselves out under your prompt, with the odd c̷u̸r̶s̵e̷d̸ letter.

The Ghost of Commits Past walks your home folder for git repos (skipping node_modules, Library and friends) and reads git log --all from each, keeping only commits where the author is you. On my machine that was 177 footprints across 35 repositories. It looks for the same date in earlier years, widening to ±1, ±3 and ±7 days; for younger histories like mine it falls back to the same day of earlier months. Once a day it also knocks on its own, with one pale line under your prompt: "Something you wrote on this day, 3 months ago, is knocking. Let it in: haunt past."

The Ghost of Commits Yet to Come is plain git plumbing: git grep for TODO/FIXME/HACK, git blame --porcelain to date the oldest ones, git stash list, git status --porcelain with file modification times, and git for-each-ref for branches nobody has touched in 60 days.

The voice is the Whisper voice built into macOS, played with say, so it's offline too.

Keeping a small ghost honest

This was the hardest part, and the part I'm proudest of.

The first time the Ghost of Commits Past spoke, it told me I'd committed to a project in 2024. My history starts in 2026. In the same breath it made up a company name, said I'd done it "for the team", and narrated its own stage directions: (pauses). A 3B model will happily invent a touching past for you, and for a tool about your memories, that's the one thing it must never do.

So the spirits now work like a séance with receipts:

  1. The evidence is printed first, exactly as it is on disk, before the model says a word. You can always check the ghost against it.
  2. The model never does date math. My code had been telling it a commit was "0 years ago", so it guessed a year. Now Python works out "3 months ago" and the model is told to use only that exact phrase.
  3. It sees less. The screen shows every memory; the model gets at most four.
  4. Stage directions are stripped as the text streams, and the spirits run at a lower temperature than Mortimer's quick whispers.

The test suite (26 tests) builds throwaway git repos with backdated commits, including someone else's commit on the same date that must be ignored, and runs everything against a fake Ollama server, so it needs no model to run.

I built Haunted Shell with an AI coding assistant, then ran it on my own history, found where the ghost lied, and kept tightening it until it didn't.

Why Open Innovation Matters for What I Built

This project should not exist on a cloud API. To work, it reads my entire git history and my shell history: every project name, every server I've SSH'd into, every half-finished idea at 1 a.m., and probably an API key I pasted once. I would never upload that to someone else's server to get a ghost story. With an open-weight model running on my laptop, I don't have to: nothing leaves 127.0.0.1. On top of that, Haunted Shell redacts tokens, passwords and user:pass@ URLs from commands and commit messages, ignores any command that starts with a space, and keeps everything in two small files I can delete.

It works with the lights and the internet off. In the demo, I turn the Wi-Fi off first. The ghosts don't notice.

It costs nothing, so it can haunt every command. Mortimer is called dozens of times a day for one-sentence replies. That's a terrible fit for a metered API and a perfect fit for a 3B model sitting warm in memory. On my Mac a whisper starts in under a second.

I can change the ghost itself. Because the model is mine, I tuned it with a Modelfile, and anyone can move the ghosts into a different open-weight model with one command (haunt model qwen2.5:3b), or use a bigger model just for the carol while the whispers stay on the small, fast one.

Memories should outlive the service that holds them. That's the part that felt right for Día de los Muertos. My commit messages turned out to be a diary I didn't know I was keeping. A tool that helps you remember shouldn't depend on a company that could change its prices or shut down. These ghosts live on my machine, and they stay as long as I want them to.

Try it (macOS)

git clone https://github.com/Olacode01/haunted-shell && cd haunted-shell
./install.sh
Enter fullscreen mode Exit fullscreen mode

Then open a new terminal tab, mistype something, and listen. When you're ready: haunt carol.

Top comments (1)

Collapse
 
olacode profile image
Toheeb Olanrewaju Olagoke •

Love this one! I went with a haunted terminal too, but turned it into "A Christmas Carol" for your shell: a Ghost of Commits Past that reads your own git history and shows you what you were building on this same day months ago, all running offline.

The hardest part was stopping the small model from making up my past. Would love your thoughts: