# I taught my terminal to haunt me, and it never leaves my laptop

> Source: <https://dev.to/ghanshyam_jha/i-taught-my-terminal-to-haunt-me-and-it-never-leaves-my-laptop-3g58>
> Published: 2026-10-28 12:08:06+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)*

Every developer has a command that keeps failing at 2 AM, and a terminal that says nothing about it.

**Wraith** is a ghost that lives in your shell. After some of your commands, it whispers one short, eerie, slightly affectionate line of commentary, powered by a small open-weight model running entirely on your own machine.

```
> rm -rf ./node_modules
  Such reckless excision would terrify even the graveyard sexton.

> git commit -m 'fix: urgent patch at 3am'
  Midnight has passed, and your eyes carry the dim pallor of tombs.
```

That is what the demo replay prints. It never blocks a command, changes one, or runs anything. It watches, it waits, and now and then it speaks.

**How I read the theme.** "Ghost in the machine" is almost literally a terminal: a place where the past lingers in your command history. So the ghost remembers. It keeps a small local log, counts how many times you've summoned the same error, and notices when you return to a corner of your disk you haven't touched in a long while. There are four ghosts to choose from:

I wanted the spooky side and the remembering side in the same tool.

You can see it without installing anything into your shell. The demo replays a scripted session and shows where each whisper came from:

```
wraith demo --debug
.---
         /     \
        | () () |     W R A I T H
         \  ^  /      The Haunted Terminal
          |||||       (runs 100% offline via Ollama)
          |||||
```

**A single-binary Go CLI that observes your shell prompt and whispers witty, contextual, offline AI commentary after errors, late-night coding sessions, and dangerous operations.**

*"Four times you have summoned this error. It still refuses to leave."*

Wraith runs **100% locally** via [Ollama](https://ollama.com). Every whisper is private and zero cents per token. Zero command strings or file paths ever leave your machine.

```
=== 👻 WRAITH SPECTRAL REPLAY (Mode: all) ===
> git status
🕯️ “A cold draught passes through the terminal; your files remain unsettled.”

> rm -rf ./node_modules
👻 [root@beyond] That command just gave your filesystem a viking funeral. Hope backups exist.

> go test ./...
📟 ABEND S0C4 IN PARAGRAPH-01. RE-READ 80-COLUMN SPECIFICATION
```

…
Wraith is a single Go binary. A prompt hook in your shell sends a small, redacted event to a local daemon on `127.0.0.1`: the command, its exit code, how long it took, the directory and the hour. The daemon decides whether the ghost should speak at all.

``` php
shell hook -> redaction -> trigger engine -> Gemma via Ollama --(over budget)--> grimoire
                                                  |                                 |
                                                  +---------> sanitizer <-----------+
                                                                  |
                                                       one dim line in your terminal
```

Hooks exist for PowerShell, bash and zsh. I developed on Windows, so PowerShell is the one that has seen real use, and bash and zsh should be treated as less tested.

The model is **Gemma 3 through Ollama**, with `gemma3:4b` as the default and `1b` or `12b` selectable. I chose the small default on purpose, because a ghost that speaks after you've typed the next command isn't haunting anyone.

The rule I followed across the whole project: **the code decides, the model writes.** Plain Go decides when to speak and works out the facts ("fifth failed build tonight"), so the model can't invent history. Gemma only turns those facts into one sentence in the voice of the chosen ghost.

A tool that sits inside your shell has to earn trust, so I set seven rules before writing any code:

`wraith haunt` shows the exact lines it will add to your profile and makes a backup first. `wraith exorcise` removes everything, and `wraith purge` deletes the local log.
And one rule for honesty: **every whisper records where it came from**, the model or the grimoire. Run with `WRAITH_DEBUG=1` and each line carries a tag like `(gemma3:4b, 420ms)` or `(grimoire)`, so you never have to wonder whether a model really said it.

I built it with Antigravity as a pair-programmer: I wrote the plan and the safety rules first, then reviewed what it produced.

I'd rather say this plainly than let you find it:

`Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` before it will run a profile script.
A command line is more personal than it looks. It holds your file paths, your hostnames, the names of projects you haven't announced, and occasionally a password typed in the wrong place. I didn't want a ghost that mails that to a server in order to be funny.

The honest cost of that choice: a small model is sometimes dull, and a busy laptop sometimes misses the time budget. That's why the grimoire exists, and why it always says so.

The idea underneath Wraith is that a ghost is just the past making itself heard. In a terminal, the past is your history: the commands that failed, the folders you left alone, the 3 AM commit.

That's why I added **Marigold**. Where the other ghosts rattle chains, she scatters marigold petals over your compiler errors. It's a small nod to Día de los Muertos, the idea that remembering something is a way of keeping it alive.
