Wraith:我讓終端機鬧鬼,而且它從不離開我的手提電腦
I taught my terminal to haunt me, and it never leaves my laptop
作者以 Go 建構 Wraith,讓終端機在指令出錯、深夜編碼或危險操作後,輸出離線 AI 評語。它透過 Ollama 在本機運行 Gemma 3,預設使用 gemma3:4b,亦可選 1b 或 12b;命令字串和檔案路徑不會離開本機。模型回應時限預設為 800 ms,超時便改用預寫訊息或保持沉默。
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
What I Built
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:
- Victorian Ghost, who calls your computer "the calculating engine"
- Grumpy Dead Sysadmin, who perished in a raised-floor server room in 1997
- Ghost of COBOL, an undead mainframe soul that remembers punchcards
- Marigold, a gentle Día de los Muertos keeper who scatters cempasúchil petals over your compiler errors
I wanted the spooky side and the remembering side in the same tool.
Demo
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
Code
.---
/ \
| () () | W R A I T H
\ ^ / The Haunted Terminal
||||| (runs 100% offline via Ollama)
|||||
👻 WRAITH: Offline AI Terminal Companion
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. Every whisper is private and zero cents per token. Zero command strings or file paths ever leave your machine.
💻 Terminal Demonstration
=== 👻 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…
How I Built It
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.
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:
- Exit codes are preserved exactly. A command that failed with 42 still failed with 42.
- Wraith is read-only. It never runs, alters or reruns a command.
- A hard time budget (800 ms by default). If the model is slow, Wraith serves a pre-written whisper from its "grimoire", or stays silent, and records which one.
- Model output is sanitized before printing: escape sequences and control bytes stripped, one line, 25 words at most.
- Command text is treated as untrusted. A command can contain "ignore previous instructions", so it goes into the prompt as quarantined data.
- Secrets are redacted before storage or inference: API keys, password flags, tokens. Commands that look sensitive skip haunting entirely.
-
Installing is opt-in and transparent.
wraith hauntshows the exact lines it will add to your profile and makes a backup first.wraith exorciseremoves everything, andwraith purgedeletes 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.
Where it's still rough
I'd rather say this plainly than let you find it:
- The demo is a scripted replay. It shows the ghost's voice and the debug tags, not a long stretch of real use. Real-world behavior on a busy laptop is the next thing I want to measure.
- Latency is the central bet. Whether a small local model can answer inside an 800 ms budget depends on your hardware. When it can't, you get a pre-written grimoire line instead, and the tag tells you so. Measured numbers for the 1B, 4B and 12B models are the next thing I'll add to the README.
- Small models can be dull. Gemma at 4B is sometimes generic, which is part of why the grimoire exists.
-
Windows needs one setting. On a fresh machine, PowerShell may need
Set-ExecutionPolicy -Scope CurrentUser RemoteSignedbefore it will run a profile script.
Why Does Open Innovation Matter?
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.
- Nothing leaves the machine. With an open-weight model running locally, "your commands stay yours" is true because of where the code runs, not because a company says so.
- Every whisper is free, which is what makes the idea possible. Commentary on a command only works if it's instant and costs nothing. Metered pricing would force the ghost to speak rarely, and I'd rather it spoke whenever the moment felt right.
- It works with the lights, and the internet, off. Once the model is pulled, the haunting continues offline.
- I can change how it behaves without touching code. Model size is a config value, and the ghosts are plain YAML files, so anyone can write their own persona.
- It can't disappear. A ghost that lives in your shell profile shouldn't vanish because an API changed its pricing or shut down. Open weights and open formats outlast any one service.
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 Spirit of It
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.
來源:DEV Community · dev.to