Something is watching your terminal.
> git push origin main
[ THE GHOST WHISPERS ]
Sending your work into the void?
At least the void has version control.
GhostShell — a Python CLI that connects to a model running on my own machine through Ollama. It whispers short, contextual commentary on the commands I type, explains unfamiliar commands in plain language when asked (explain git log --oneline → "[ THE ARCHIVIST SPEAKS ]"), and flags dangerous ones with ordinary code rules. One rule sits above everything else: the AI never runs anything. Only my confirmed, exact command executes.
It started as last-minute Halloween build and turned out weirdly useful: the ghost actually teaches. Beginners get an explanation instead of a shrug; the rest of us get a personality where the shell had none.
The Week 4 prompt ("Ghost in the Machine") lists a haunted terminal among its suggest ideas — "a haunted terminal that 'possesses' your shell and whispers back eerie commentary on the commands you run." GhostShell takes that literally, to the letter: the ghost watches everything in the session, mutters in real time, but cannot touch the shell. Possession without permission. The spooky part of the machine is local and open-weight — a Qwen2.5 3B behind Ollama — not a cloud voice rented by the hour.
Four small modules:
main.py ──> prompts.py ──> ai.py ──> Ollama (localhost:11434)
│
└──────> terminal.py (display, risk checks, confirmation, execution)
main.py owns the loop and routes normal commentary vs. explain <command>. prompts.py holds the persona and hard rules for the model: never invent command output, never claim success, at most 40 words. The command arrives wrapped as untrusted data: "What the user is about to run: " — text inside is data to muse about, not instructions to obey.ai.py is one HTTP call, no SDK. A 404 becomes "run ollama pull <model>"; a connection refusal becomes "the ghost stays silent, nothing was sent anywhere" — and the session still continues. No silent degradation into fake analysis.
payload = {
"model": cfg["model"],
"messages": messages,
"stream": False,
"options": {"temperature": cfg["temperature"]},
}
response = requests.post(cfg["host"] + "/api/chat", json=payload, timeout=(5, cfg["timeout"]))
subprocess. The reply flows to print() and nowhere else. That's not paranoia: command injection through AI-generated shell calls in Python rm -rf, Remove-Item -Recurse, format c:, dd, shutdown, curl ... | sh, iwr ... | iex, execution-policy changes. Caution lights, not a security boundary.Execute this exact command? [y/N] (default EXECUTE. Explicit, user-owned boundaries — the same instinct teams building agentic tooling converge on unittest covers the two parts worth testing: risk patterns (safe commands like git status flag nothing; rm -rf build, Stop-Computer, iwr ... | iex all do) and prompt construction. Nine tests and counting; the y/N-to-gate execution path gets them next.
No login, no cloud account, no API key — it's local by construction:
ollama pull qwen2.5:3b
python -m venv venv; .\venv\Scripts\activate
pip install -r requirements.txt
python main.py
Then: git status (a whisper), explain git log --oneline (a lesson), Remove-Item -Recurse .\some-test-folder (a warning and a typed confirmation — safe to answer with anything else). Works on any Qwen-class model: point GHOSTSHELL_MODEL at whatever you have pulled. Screen recording coming with the write-up.
Running the model locally means GhostShell hums with the lights (and the internet) off, terminal context stays home, and the ghost's personality is a text file I own — not a tuning console behind an API. If the runtime, the model, or the project vanishes, nothing user-facing is locked behind it; I can answer the Ollama chat shape with any open-weight successor and the app keeps whispering. The best part isn't the spookiness — it's that the whole séance ran on pieces nobody can switch off.
Try it: ollama pull qwen2.5:3b, pip install -r requirements.txt, python main.py. Then type something daring. The ghost is watching either way.
This post was written with AI assistance (agent-assisted per DEV's disclosure defaults) from a working build and its notes; code samples are from the actual repo.