DEV Community

Anshu Pandey
Anshu Pandey

Posted on Edited on

GhostShell: a haunted terminal that "possesses" your shell (Hacktoberfest Week 4)

Hacktoberfest Open-Source AI Challenge: Ghost in the Machine Submission πŸ‘»πŸŒΌ

 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.
Enter fullscreen mode Exit fullscreen mode

What I built

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.

How I interpreted the theme

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.

The engineering, briefly

Four small modules:

main.py ──> prompts.py ──> ai.py ──> Ollama (localhost:11434)
   β”‚
   └──────> terminal.py   (display, risk checks, confirmation, execution)
Enter fullscreen mode Exit fullscreen mode
  • 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"]))
Enter fullscreen mode Exit fullscreen mode

The safety design, which is the actual project

  1. Model text never touches subprocess. Only the string I typed β€” and confirmed β€” reaches subprocess. The reply flows to print() and nowhere else. That's not paranoia: command injection through AI-generated shell calls in Python is a documented failure class.
  2. Deterministic risk checks in plain code. ~18 regex patterns β€” rm -rf, Remove-Item -Recurse, format c:, dd, shutdown, curl ... | sh, iwr ... | iex, execution-policy changes. Caution lights, not a security boundary.
  3. Two-stage confirmation. Every command asks Execute this exact command? [y/N] (default no). Anything flagged additionally requires typing EXECUTE. Explicit, user-owned boundaries β€” the same instinct teams building agentic tooling converge on here.
  4. The model gets context, never authority. Flagged commands tell the ghost "deterministic safety checks flagged this command: ... (these are code-based flags, not your judgment)". It can mention the risk in its whisper; it cannot downgrade it.

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.

How to test (for judges)

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
Enter fullscreen mode Exit fullscreen mode

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.

Why open innovation matters for this

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.

Top comments (0)