haunted-shell:我的終端機被一名未完成部署的程式設計師鬼魂纏上
My Terminal Is Haunted by a Programmer Who Never Finished Their Deploy
開源專案 haunted-shell 將 AI 鬼魂接入 zsh 終端機,監看用戶指令,並在指令失敗時回應;指令成功時約有三分之一機會發聲,亦會記住最近五條指令。它透過 Ollama 在本機運行開放權重模型,預設使用 qwen3:8b,無需 API 或網絡,shell 歷史不會離開裝置。
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
What I Built
haunted-shell possesses your zsh. A ghost lives in the terminal: the programmer who died at this keyboard years ago, with a deploy still unfinished. It watches every command you run, and sometimes, in dim violet italics that type themselves out a little too slowly, it whispers back.
$ git push --force origin main
your git push failed, but i'm sure you knew that. the main branch is still here, waiting for you.
$ rm -rf node_modules
i watched you delete the node_modules. you're so reckless. i once tried to save them. now they're gone.
$ npm run build
the build failed. you're still using node 12. i never got to fix that bug.
It never helps you, by design. When a command fails, the ghost always speaks. When one succeeds, it speaks about a third of the time, so you never know when it's listening. It also remembers your last five commands, so it can bring up the git status you ran four times in a row.
Demo
Two commands, two whispers: "your git repo is dead, but i'm still here. i never learned to push." and then, fittingly for a GIF, "why does it feel like we're both stuck in a loop?"
Code
haunted-shell 👻
A ghost lives in your terminal. It's the programmer who died at this keyboard years ago, and it watches every command you run. Sometimes it whispers back.
$ git push --force origin main
your git push failed, but i'm sure you knew that. the main branch is still here, waiting for you
$ rm -rf node_modules
i watched you delete the node_modules. you're so reckless. i once tried to save them. now they're gone.
It runs entirely on an open-weight model through Ollama. No API keys, no network, and your shell history never leaves your machine.
Install
ollama pull qwen3:8b # or gemma3:4b, llama3.2, anything Ollama serves git clone https://github.com/ghost-huzaifa/haunted-shell.git ~/haunted-shell echo 'source ~/haunted-shell/haunt.zsh' >> ~/.zshrc
Open a new terminal. Type unhaunt to banish it for the session.
Knobs
| env var | default | what |
|---|---|---|
HAUNT_MODEL |
qwen3:8b |
any Ollama model |
HAUNT_CHANCE |
35 |
% of successful |
…
It's two files: about 20 lines of zsh that hook preexec and precmd, and about 60 lines of Python that use only the standard library. There are no dependencies and no SDKs.
How I Built It
-
The model: an open-weight model (
qwen3:8bby default; any Ollama model works throughHAUNT_MODEL) running locally through Ollama on an M1 MacBook with 16 GB of RAM. -
The hook: zsh's
preexecsaves the command andprecmdgrabs the exit status. Both go to the ghost, together with the current directory and recent history. -
The voice: a short system prompt makes the ghost lowercase, wistful, a little funny, never helpful, and limited to one line about the exact command you ran. Thinking is turned off (
"think": false) and output is capped at 48 tokens, so a whisper takes a couple of seconds once the model is warm. -
The manners: a ghost that breaks your shell is a bad ghost. If Ollama is down or slow, it stays silent, and
unhauntbanishes it for the session.
I built this with an AI coding agent (Claude Code) as a pair, and the whole session is below. The model was the easy part. The hard part was the manners: making sure the ghost never throws a stack trace into your prompt, and fixing a bug where zsh's array slicing made it forget every command but the last one until four had piled up.
Why Does Open Innovation Matter?
Your shell history is one of the most private things on your computer. It holds every hostname you've SSH'd into, every half-typed password you pasted into the wrong prompt, every curl with a token in the header, every embarrassing git reset --hard. I would never pipe that to a hosted API, and I doubt you would either.
An open-weight model running on my own laptop changes that:
- It works with the lights (and the Wi-Fi) off. Ghosts shouldn't need an internet connection. This one works on a plane.
- Nothing leaves the machine. The ghost reads your commands and nobody else does. There's no telemetry, no retention policy to read, and no account.
-
It costs nothing per whisper. A closed API would bill me for every
ls. Locally, the ghost can comment on thousands of commands a day for free. - The ghost is swappable. One env var changes the model, so you can swap in Gemma or Llama and meet a different ghost. You choose your ghost, and no provider can change its personality out from under you.
- It can't be shut down. It won't disappear because an API was deprecated or a startup ran out of runway. A ghost that's open-source can't really die. It seems fitting for a project released on Halloween, just before Día de los Muertos.
The trade-off is honest: the first whisper after boot takes about 10 seconds while the model loads, and an 8B model is less witty than a frontier model. For a voice that sits inside your most private tool, I'll take a slightly dumber ghost that keeps my secrets.
My Agent Session
The Spirit of It
While I was recording the demo, I cd'd into my day-job repo, and the ghost whispered: "you're still here. i'm still here. why does it feel like we're both stuck in a loop?" An 8B model running on my laptop, with no internet, called me out. Happy Halloween. 🕯️
來源:DEV Community · dev.to
