This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
What I Built
Séance Shell is a haunted terminal. A small ghost lives in your Bash or Zsh session, watches for the moments that matter, and murmurs a single eerie sentence about what just happened.
It reacts to two kinds of events:
-
Destructive-looking commands like
git reset --hard,git clean -fd, orrm -
Failed builds and tests like
pytest,npm run build, orcargo build
Once the command has finished, the ghost speaks:
$ git reset --hard HEAD~1
ghost: the past has accepted your changes, and forgotten your future.
That's the whole product. The ghost is a companion for reflection, not an assistant for execution. It never suggests commands, never runs anything, and never offers advice.
How I read the theme: the prompt suggested "a haunted terminal that possesses your shell and whispers back eerie commentary." I wanted that, but with restraint. Most AI tools are loud and eager to help. A good ghost lingers at the edge of the room, says one unsettling thing, and goes quiet. Séance Shell is a ghost that knows its place.
Code
Séance Shell 👻
A quiet, local-AI terminal companion that offers one short reflection after selected commands. The ghost is atmospheric, not an assistant: it gives no advice, runs no generated text, and never retries a command.
$ git reset --hard HEAD~1
ghost: the past has accepted your changes, and forgotten your future
Reflections are generated independently by Ollama on your machine with gemma3:latest. Model output is validated before display. If the local model is unavailable, the reflection is skipped.
What it does
- Notices selected destructive-looking commands and failed build/test commands.
- Reflects only after the shell has already completed a command; it never re-runs it.
- Sends Ollama a category, outcome, and—only for an explicit
seance reflect --contextrequest—short sanitized context. Shell hooks do not send the command text to the model. - Requires one sentence, at most 15 words and 180 characters; malformed output is discarded.
- Uses dim terminal text when…
To run it locally you need Ollama and the gemma3:latest model. The shell hook works without the model, so the ghost only goes silent if Ollama isn't running.
How I Built It
The open-source pieces are what make this work:
- Ollama runs inference locally.
-
Gemma 3 (
gemma3:latest), Google's open-weight model, is the default. - A Bash/Zsh hook detects events after the shell has finished a command.
No cloud API, no hosted inference, no account. Three design decisions shaped the build.
1. The model never sees your command
The shell doesn't send the raw command string to the model. It sends a structured description:
- category: destructive or failed-build
- status: succeeded or failed
- context: optional, and sanitized first
The model gets enough to set a mood but nothing it could be tricked by or leak. It is not a coding agent and can't be steered by arbitrary shell content.
2. The output is validated aggressively
The model is asked for one sentence, at most 15 words and 180 characters. If the response is malformed, multi-line, or too long, it's discarded and the ghost stays silent. The text on screen is a constrained artifact, not whatever the model felt like saying.
3. A ghost, not an agent
Séance Shell never retries commands, never executes anything, and never reinterprets what you did. It's a passive observer. That modesty is what makes it usable in a place where you're making decisions at speed.
Why Does Open Innovation Matter?
A terminal is about as personal as software gets. It holds your file paths, repo names, half-finished experiments, and the commands you'd rather not explain. An always-on ghost watching that is only acceptable if it lives on your own machine.
Open-weight models made that possible in three ways:
- It works with the lights off. There is no network call in the loop, so the ghost haunts you on a plane, in a basement, or during an outage.
- Your context stays on your machine. Even with command text withheld, I wouldn't want a terminal's activity flowing to a server I don't control. With a local model I don't have to take anyone's word for it, and I can read exactly what gets sent.
- I control the personality. The ghost's voice depends on the prompt, the validation rules, and the model. With open weights I can swap Gemma for another model or tighten the constraints without asking a vendor, and nothing can be deprecated out from under it.
A closed API could have written the sentences. It couldn't have given me a ghost that is private, offline, and mine, and that's the part that makes it feel like a haunting rather than a service.
The Spirit of It
The first time it fired, I ran git reset --hard HEAD~1 on a throwaway branch and the ghost answered: "the past has accepted your changes, and forgotten your future." It was a small moment, but the one-line reminder that I had just erased something did what no warning dialog ever has. It made me pause.
Prize Categories
Best Use of Gemma: Gemma 3 runs locally through Ollama as the model behind every one of the ghost's reflections.
Top comments (1)
Terminal personality is fun until it blurs what will execute. The safest interaction model keeps generated suggestions visibly separate from shell input, requires an explicit run action, and logs the final expanded command. That preserves the charm while keeping the terminal’s authority legible to the user.