GhostShell: the terminal remembers the bug, and it does not press the keys Developer Abishethvarman built GhostShell, a local-first terminal companion that stores past errors in a SQLite ledger, compares new tracebacks against earlier incidents, and holds suggested fix commands for explicit approval before running them. Inference runs on a loopback Ollama server with no cloud model client or telemetry, and the developer reports that pointing it at gemma3:4b returned schema-validated JSON, though the fully offline path was not verified. This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine https://dev.to/challenges/hacktoberfest-week4-2026-10-26 GhostShell is a terminal companion for the bug you already met. The tagline is “Your terminal remembers what you forget.” You paste a traceback, say what you were doing, and point it at one project directory. It writes a structured reading: a title, a category, ranked guesses, the lines those guesses rest on, what it has not seen, a risk level, and a check you can run afterward. If a similar incident is already in the local ledger, the screen names that incident’s id. It does not announce that the old fix will work again. The ghost is the voice. The evidence is the constraint. Suggested commands are shown first. Nothing runs until you approve it, and a local policy check can still refuse. I read the theme as memory with a boundary. A haunted machine that whispers fixes and then types them would be a costume on a chatbot. The interesting ghost is the one that remembers the earlier failure and still hands you the keyboard. GhostShell is a local terminal app. There is no hosted website. This silent video is the interface itself, captured from the app with the synthetic phantom project and the rule-based reader, so it does not wait on a model. It runs about one minute: the ledger, the lantern reading with the traceback quoted back, the two earlier incident ids, the pip show command held for approval, the pattern, and the ledger rows. The file in the repository is docs/demo/ghostshell-demo.mp4 . The player above works after that file is pushed to main . python -m venv .venv .venv\Scripts\activate python -m pip install -e ". dev " $env:GHOSTSHELL HOME = "$PWD\demo-home" python -m ghostshell.app --seed-demo --seed-demo inserts five fake incidents for examples/phantom app . That folder imports a module named lantern on purpose, fails an assertion in ritual.py , and contains one file that is not valid Python. There are no credentials in it. The walkthrough with expected text is docs/DEMO SCRIPT.md . For the fix review, assess python -m pip show lantern and approve that read-only check. Leave python -m pip install lantern unapproved. The demo is not supposed to install a package. On this machine, Ollama 0.6.6 already had gemma3:4b . Pointing Settings at that tag and submitting the same lantern traceback returned JSON that validated: a title, a category, hypotheses, and command argument lists. The source line said local AI and named the model. The pictures above are the rule-based path, because the screenshot pilot turns Ollama off. I have not disconnected the network and then relaunched, so I am not calling the offline path verified. Your terminal remembers what you forget. Every bug leaves a trace. GhostShell is a local-first terminal companion for investigating errors, recalling earlier incidents, and reviewing a fix before anything runs. The personality is a ghost. The reasoning is the evidence you pasted, the files you selected, and the incidents already stored on this machine. This build is for the Hacktoberfest 2026 Open-Source AI Challenge, Week 4: “Ghost in the Machine.” Inference stays on a loopback Ollama https://ollama.com server. There is no cloud model client and no telemetry. Error output disappears into a scrollback buffer. The next time the same import fails, or the same test breaks, the earlier context is gone. Sending that traceback to a hosted model also sends whatever the log happened to contain. GhostShell keeps a SQLite ledger on disk, compares a new error with those rows, and refuses to run a suggested command until… Repository: https://github.com/Abishethvarman/GhostShell https://github.com/Abishethvarman/GhostShell License: MIT. Python 3.11+, Textual, Rich, Pydantic, SQLite, and pytest. Model weights are not in the repository. php flowchart TD user Developer -- ui Textual UI ui -- redact Redaction and size limits redact -- memory Ledger search memory -- manager Model manager manager -- ollama Loopback Ollama manager -- rules Rule-based reader ollama -- parser Pydantic parser parser -- ui rules -- ui ui -- policy Command policy policy -- runner Argument-list process ui -- ledger SQLite ledger The only HTTP client talks to 127.0.0.1 , localhost , or ::1 . A cold Gemma load once answered HTTP 500. The client retries that once, then tries plain JSON mode if a schema is rejected. If the reply still is not valid JSON, the rule-based reader answers and says so. if exc.code == 500 and isinstance body.get "format" , dict : try: return self. request "POST", "/api/chat", body=body, timeout=timeout except urllib.error.HTTPError as second: exc = second if exc.code in {400, 500} and isinstance body.get "format" , dict : relaxed = dict body relaxed "format" = "json" Memory ids are replaced after the model replies. Whatever id the model wrote is discarded. The ids on screen are the ones the ledger search returned. analysis.memory incident ids = item.incident id for item in matches note += " A previous fix is not assumed to resolve this incident." Commands run as an argument list with shell=False , a timeout, and a capped capture. A suggestion that arrives as one shell string is displayed and cannot be run. The open-source AI is local inference through Ollama https://ollama.com/download . The preferred family is Gemma. Settings can select gemma2:2b the configured default, a small tag , gemma3:4b , gemma2:9b , or qwen2.5:3b . GhostShell does not run ollama pull . If the selected tag is missing, the dashboard lists what is installed and the séance uses the deterministic reader. The project is built around that call, with the ledger in front of it: A closed debugging API wants the traceback. Tracebacks contain paths, hostnames, tokens, and the occasional password someone echoed. Sending that away so a chat window can say “try reinstalling” is a bad trade, and the answer disappears when the tab closes. An open-weight model behind Ollama changes the shape of the tool: gemma3:4b . Open weights are what make the memory acceptable. The ghost can keep the earlier bug because the ledger never leaves the machine, and it still has to ask before it touches the project. I have not published an agent-session transcript for this build, so there is no agent-session embed yet. The decisions are in the repository: loopback only, no automatic model download, memory ids taken from SQLite rather than from the model, and no command without an approval and a second policy check. The moment that landed was not a jump scare. It was the second lantern failure. The synthetic app imports lantern and fails. The ledger already had that traceback, marked with what someone claimed they did last time. GhostShell did not say the old install would save this one. It quoted the new error, printed the old incident ids, and stopped at python -m pip show lantern until that read-only check was approved. That is the haunting I wanted. The machine remembers the trace. It does not get to finish the ritual. Gemma is the model the app is set up to call, and gemma3:4b through local Ollama produced a validated investigation on this machine.