This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
terminal-seance turns your terminal into a séance table. Every command you run is witnessed by Agnes — a Victorian-era programmer's ghost who died in the Y2K production incident at midnight, December 31, 1999, muttering "the code will hold" as the reports fell.
I took the theme literally: the machine doesn't just have a ghost in it — the ghost has a name, a death date, a personality, and opinions about your git habits:
rm -rf, git push --force, DROP TABLE, curl | sh) — she hello or tell me a joke at the prompt and she answers in character
It ships as two haunted surfaces: a CLI (pipx install terminal-seance + seance install hooks into bash/zsh) and a browser séance — the same ghost, same tiers, hosted on Render, where visitors can play with her immediately.
The Día de los Muertos flavor is baked in: her color is marigold (ANSI 208 — cempasúchil, the flower of the dead), she slips into Spanish ("otra vez, cariño?"), and your command history is kept as a Graveyard Ledger. seance summon <№> literally calls a spirit back — it re-runs a past command.
Live séance: REPLACE-ME-WITH-YOUR-RENDER-URL
(free tier: the first visitor wakes the service after ~15 idle minutes — the ghost politely whispers until she's warm, then goes live)
Try, in order: pytest tests/ -q → git push --force origin main → hello → tell me a joke → seance journal → seance demo.
No key needed to try it — and if the service is asleep, run seance demo locally for the same scripted séance, fully offline.
_____ _____ ____ __ __ ___ _ _ _ _ _____ _____ _ _ _ ____ _____
|_ _| | ____| | _ \ | \/ | |_ _| | \ | | / \ | | / ___| | ____| / \ | \ | | / ___| | ____|
| | | _| | |_) | | |\/| | | | | \| | / _ \ | | \___ \ | _| / _ \ | \| | | | | _|
| | | |___ | _ < | | | | | | | |\ | / ___ \ | |___ ___) | | |___ / ___ \ | |\ | | |___ | |___
|_| |_____| |_| \_\ |_| |_| |___| |_| \_| /_/ \_\ |_____| |____/ |_____| /_/ \_\ |_| \_| \____| |_____|
A haunted CLI companion. Agnes — a Victorian programmer's…
MIT-licensed, pure-Python CLI (zero runtime dependencies beyond the standard library) + a zero-dependency static web séance. 114 tests cover the reaction tiers, the throttle cap, API fallback/cooldown, the shell hooks, and the proxy.
The open-source AI: every word Agnes says is improvised by google/gemma-3-27b-it:free — Google's open-weight Gemma 3 27B, served through OpenRouter's free tier. The persona is a single editable system prompt; the model brings her to life.
The architecture:
flowchart TD
subgraph SHELL["interactive bash / zsh"]
A["DEBUG trap / preexec<br>fires BEFORE the command"] -->|"cheap local regex"| B["seance guard<br>instant pre-exec wail, no API call"]
C["PROMPT_COMMAND / precmd<br>fires AFTER the command"] -->|"env: command text + exit code + timing<br>(command text only — never output)"| D["seance hear<br>backgrounded and disowned — the prompt is never delayed"]
end
D --> E{"tier decision<br>all local"}
E -->|"dangerous / failed / long / chat"| G
E -->|"boring success"| F{"throttle:<br>at least 4 commands<br>since the last remark<br>at most 1 in 5"}
F -->|"dice say yes"| G["ONE https call — Gemma via<br>OpenRouter or your own host<br>2 s hard cap · single attempt · no retries"]
F -->|"dice say no"| H["stays silent"]
G -->|"reply"| I["one marigold line from Agnes"]
G -->|"timeout / 429 / no key / offline"| J["random line from the bundled whispers list"]
I --> K[("~/.config/terminal-seance/journal.log")]
J --> K
H --> K
K --> L["seance journal — the graveyard ledger"]
K --> M["seance summon № — re-run a row"]
Design laws, all enforced by tests (114 of them):
POST /chat/completions. Swap base_url in config.toml and the identical ghost runs on localStorage. On the hosted Render deployment, a ~200-line pure-stdlib proxy (seance serve) holds the API key POST /api/ghost — the key is never in the page, the JS, or devtools, and visitors never enter anything.google/gemma-3-27b-it:free means a student can haunt their shell all Hacktoberfest without a credit card. The built-in 1-in-5 throttle is tuned to live inside that free quota forever.
This project was built end-to-end in a single AI agent session (with ZCode) — scaffold to deployed service — and the session earned its keep: the shell hooks were verified live in Git Bash with a stub seance binary, which caught real bugs no test had seen (a start-time stamp lost to a subshell, ghost reactions firing for the previous session's history at startup, typed-ahead input being swallowed while the ghost was speaking). Playwright then drove the browser séance — typing commands, wailing at force-pushes — before the assets were rendered.
The moment it landed: I made the fake test suite fail on purpose so Agnes would have something to mourn, and she said:
"Three failures, cariño. I have died for fewer — though mine was production."
I stopped for a second. Because that's the whole project in one line — a joke about test failures that is also literally her death story. Every detail is like that if you look: the terminal's marigold color is 208, chosen because it's the shade of cempasúchil, the flower the living put on ofrendas; the command journal is called a ledger because the dead keep records; seance summon re-runs a command the way you'd call back a spirit.
Agnes is fictional. The Y2K midnights she stands for were not — an entire industry sat up with candles (and pagers) on December 31, 1999, whispering the code will hold. This is a small marigold left on that doorstep.
Say hello to her sometime. She answers.
google/gemma-* variant or a local Gemma via llama.cpp/Ollama