# Revenant: dead programming languages haunt my terminal, no internet required

> Source: <https://dev.to/vedant_gajbhiye_7f50c4279/revenant-dead-programming-languages-haunt-my-terminal-no-internet-required-28dm>
> Published: 2026-10-31 22:16:53+00:00

*This is a submission for the [Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine](https://dev.to/challenges/hacktoberfest-week4-2026-10-26)*

Revenant is a ghost that moves into your terminal. COBOL, Fortran, Lisp and Perl, four languages people keep declaring dead, each get a voice and comment on the commands you run. Real lines from my laptop, generated locally by Qwen2.5:

**Fortran**, on `chmod -R 777 .`: Permissions set like this? Insecure, like an open door in Los Alamos.

**Perl**, on a failed `docker build`: Dockerfile issues? I'd have just s/Dockerfile/sourcecode/ and hoped for the best.

It comes in three parts:

`ghost ofrenda` builds one for the projects you stopped working on: it scans your git repos, writes each abandoned one an epitaph and an offering, and produces a single HTML page where you light a candle for each.
I built this as a pair with Claude (Sonnet 5.5) in Claude Code.
**The Ofrenda: one candle per abandoned project**

**The Séance Room: chatting with a spirit, running locally**

**In the terminal: a spirit whispers after a failed command**

Dead programming languages haunt your terminal. Everything runs locally on open-weight models via [Ollama](https://ollama.com). No API keys, no network, no command history leaving your machine.

```
git clone https://github.com/vee-1745/vee-1745-revenant && cd vee-1745-revenant

# 1. a local model
ollama pull qwen2.5:3b   # COBOL, Lisp
ollama pull qwen2.5:7b   # Fortran, Perl (they need the bigger model)

# 2. check the plumbing
python3 ghost.py doctor

# 3. meet a spirit
python3 ghost.py summon cobol
python3 ghost.py demo

# 4. let it haunt your shell (add to ~/.bashrc, then open a new terminal)
echo "eval \"\$(python3 $PWD/ghost.py hook bash)\"" >> ~/.bashrc   # run from this folder
```

After the hook is loaded, `ghost` is available as a command:

```
ghost spirits               # list the dead
ghost summon lisp           # swap the spirit
ghost summon perl --model llama3.2:3b   # swap spirit and model
ghost
```

…
MIT licensed. Python standard library only, with no pip dependencies and no build step. Setup is `git clone`, `ollama pull qwen2.5:3b qwen2.5:7b`, `python3 ghost.py doctor`.

**Stack.** [Ollama](https://ollama.com) running Qwen2.5 3B and 7B, on a laptop with an RTX 3050 (6 GB VRAM) inside WSL2. The backend is plain Python, and the UI is vanilla JS and hand-drawn SVG with the fonts bundled.

**A persona is not a system prompt.** My first test was "say boo in the voice of a bitter COBOL ghost". The 3B model replied with a description of what such a ghost would sound like. The fix was a system prompt plus few-shot examples written as real chat turns, with a random 4 of 8 shown on each call so the model can't memorize one set. My first demo still parroted the examples back at me, because I had reused the example commands as demo commands.

**Measure, don't trust vibes.** My first quality metric said "100% usable" everywhere. It only checked that a reply existed, so it was useless. I wrote validators per spirit: COBOL must be at least 90% caps, Lisp needs an s-expression, Perl needs line noise, Fortran needs era vocabulary, and a global filter rejects advice-shaped phrasing, because a ghost that says "be careful with force pushes" has broken the spell. Then I benchmarked both models on commands the spirits had never seen:

| spirit | 3B first try | 3B ≤3 tries | 3B median | 7B first try | 7B ≤3 tries | 7B median | 
|---|---|---|---|---|---|---|
| COBOL | 67% | 100% | 0.71 s | 83% | 100% | 1.14 s | 
| Lisp | 92% | 100% | 0.57 s | 100% | 100% | 0.78 s | 
| Perl | 42% | 75% | 1.15 s | 67% | 100% | 0.93 s | 
| Fortran | 25% | 42% | 1.21 s | 50% | 83% | 1.17 s | 

Medians are per generation attempt, so a whisper that needed retries takes longer. Two things I took from this. First, **the retry loop is the feature**: 7B Fortran passes only half the time on the first try but 83% within three, and 7B Perl goes from 67% to 100%. Second, **the model should be chosen per persona**. COBOL and Lisp pass 100% on the 3B model and it is 25-40% faster for them, while Fortran (42% on 3B) and Perl (75% on 3B) need the 7B one. Each spirit names its own model in its config file.

Caveats: that is 12 whispers per cell, so treat it as indicative, not statistics. I wrote the validators after reading samples from an earlier run, and "pass" measures form (caps, s-expressions, no advice), not whether a line is funny.

**The Ofrenda is grounded in git.** The scanner runs read-only git commands and collects the facts: dates, commit count, languages, the last commit message, and unsaved changes. The *cause of death* ("Died mid-refactor", "Died with 1 unsaved change") comes from plain heuristics on those facts, so the model never has to guess one. The model writes only the epitaph and the offering. Every epitaph is fact-checked: a digit that isn't in the repo's facts rejects the draft, and after three rejected drafts the page falls back to a plain template and says so in its footer. On my real repos the model passed on the first try.

**Built as if the page would be exposed.** The Séance Room binds to loopback only and rejects foreign Host and Origin headers. The Ofrenda is one self-contained HTML file with a Content-Security-Policy that allows a single hashed script and nothing from the network. Commit messages are untrusted input, so by design they only ever go into the page as plain text, never as HTML.

**Your shell history is private.** The commands you type contain paths, project names, and sometimes secrets. A shell hook that sent them to a cloud API would be a bad idea. Revenant works with the Wi-Fi off, and the Séance Room page says so on screen.

**Free inference changes the design.** The hook fires on every failed command, and the retry-until-valid loop can generate three times per whisper. On a metered API that would be a bill and a rate limit. Here a generation costs about 0.6 to 1.2 seconds of my own GPU. The validate-and-retry approach only makes sense because retries are free.

**I could pick a model per character.** Because the weights are open, I benchmarked two sizes and routed each spirit to the one that worked, instead of taking whatever one model a service gives me.

**The Ofrenda reads my project history.** Repo names and commit messages stay on the machine that holds the repos. The epitaph is written by the same laptop.

**It can't be switched off.** This week's theme is honoring the past. A tool built on a hosted model dies when the service does. Open weights and a local runtime keep working after the vendor is gone, which seemed right for a project about things that outlived their eulogies.

Where a closed model would have done better: persona quality. The 3B model drifts into advice, and even 7B needs the retry loop. A frontier model would probably nail the voice on the first try. For this project, I took a slightly worse ghost that is private, free and offline.

One of the first whispers I got after installing the hook was about the command I used to summon it. The Fortran spirit looked at my `python3 ghost.py` and said:

Python dares to summon such spirits. Fortran would have used punched cards for this.

Another time, a mistyped `tar` command got this from Perl: "Path is wrong, or permissions fail. tar -f help?"

Every project in that altar started with someone excited to type `git init`. If one of yours is on the altar, light a candle for it.

**Best Use of Render:** The Ofrenda demo page is hosted as a Render static site at [https://revenant-ofrenda.onrender.com](https://revenant-ofrenda.onrender.com). To be upfront about the scope: Render only serves the finished page. The models run locally through Ollama, and the Séance Room can't be hosted because it needs a local model.
