PhantomShell: the haunted terminal that whispers the fix A developer built PhantomShell, a shell hook that triggers when a command fails, printing an ASCII tombstone, a one-line explanation of the error, and a copy-pasteable fix command. Its default model is Gemma 3 4B running locally via Ollama, but a deterministic "omen engine" handles common failures such as mistyped commands, missing Python modules, occupied ports and SSH key errors without invoking the model at all. The hook avoids eval and subprocess, bounds its timeout, restores the original exit code and passes Ctrl+C through. Built for the Hacktoberfest Open-Source AI Challenge: Week 4 https://dev.to/events/82 — theme: Ghost in the Machine . At 2 a.m. the only thing still talking in my terminal is the error message. gti: command not found — five words, no context, no apology, no hint about what it wanted. It says what went wrong and stays completely silent about what should have happened. It is, in the most literal sense available to me, a ghost: a voice from a dead process, speaking a language of exit codes and stack traces, saying nothing that matters. Every shell tool I have used treats that voice as raw material. They parse it, they grep it, they open a ticket with it. I built something that listens to it instead. PhantomShell is a small ghost that lives in your shell hook. When a command fails, it stirs: an ASCII tombstone, one dim sentence about what you did wrong, and one clean, copy-pasteable command that fixes it. The default brain is an open-weight model running on your own machine — Gemma 3 4B through Ollama — so it works with the Wi-Fi off, it never sees your data, and it costs nothing to run. But the part I am actually proud of is not the model. It is that this project has a second brain which costs zero and cannot be turned off : a deterministic "omen engine" that fixes the most common failures without asking anything at all. That is a real run: gemma3:4b , open weights, on an AMD laptop with no GPU. The whisper was written by the model. The fix was not. The brief for this week is Ghost in the Machine , and it stretches from Halloween on October 31 through Día de los Muertos on November 1 and 2 — the stretch of the year when the line between past and present feels a little thinner. It also lists some very good suggestions, the first of which is: A haunted terminal that "possesses" your shell and whispers back eerie commentary on the commands you run. I did not have to stretch to reach that one. The idea was already the obvious one, and I want to be honest about why: the terminal is the single most haunted room in modern life. It is a place where you talk to things that no longer exist, using commands written by people who died before you were born, in a language POSIX sh that is officially in maintenance mode. Every apt upgrade is a séance with the 1990s. So the ghost is not decoration. The ghost is the part of the machine that outlived the person who wrote it . That gave me the design rule for the whole project: the haunting must be optional, the fix must not be. A toy that only works when the model is up is a toy. A ghost that can still help when the model is dead, the network is down, and the laptop is on a train, is a tool. | Failure you hit | What the ghost says | What it hands you | |---|---|---| | gti status | a line about calling into the dark for a word no binary answers to | git status | | ModuleNotFoundError: No module named 'yaml' | something about an import that was never invited | python3 -m pip install pyyaml | | EADDRINUSE :::3000 | a complaint about a port already occupied | lsof -i :3000 | | Permission denied publickey | a mutter about locked doors and handshakes | ssh-add ~/.ssh/id ed25519 | | cat: notes.txt: No such file or directory | a remark about asking for a ghost of a file | ls -la in the current directory | | exit code 130 | "The spell was interrupted." | nothing — it does not invent a fix | Two rules make the rest of the design possible: eval , no subprocess , no shell interpolation of model output anywhere in the codebase. 0 , the timeout is bounded, your original $? / $LASTEXITCODE is restored, and Ctrl+C is passed straight through. A hook that can hang or crash a prompt gets uninstalled within a day. php flowchart TD A command fails