{"slug": "ghostshell-the-terminal-remembers-the-bug-and-it-does-not-press-the-keys", "title": "GhostShell: the terminal remembers the bug, and it does not press the keys", "summary": "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.", "body_md": "*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)*\n\nGhostShell is a terminal companion for the bug you already met. The tagline is “Your terminal remembers what you forget.”\n\nYou 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.\n\nThe 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.\n\nI 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.\n\nGhostShell 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.\n\nThe file in the repository is `docs/demo/ghostshell-demo.mp4`. The player above works after that file is pushed to `main`.\n\n```\npython -m venv .venv\n.venv\\Scripts\\activate\npython -m pip install -e \".[dev]\"\n$env:GHOSTSHELL_HOME = \"$PWD\\demo-home\"\npython -m ghostshell.app --seed-demo\n```\n\n`--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.\n\nThe 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.\n\nOn 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.\n\n**Your terminal remembers what you forget.**\n\nEvery 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.\n\nThis 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.\n\nError 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.\n\nGhostShell keeps a SQLite ledger on disk, compares a new error with those rows, and refuses to run a suggested command until…\n\nRepository: [https://github.com/Abishethvarman/GhostShell](https://github.com/Abishethvarman/GhostShell)\n\nLicense: MIT. Python 3.11+, Textual, Rich, Pydantic, SQLite, and pytest. Model weights are not in the repository.\n\n``` php\nflowchart TD\n    user[Developer] --> ui[Textual UI]\n    ui --> redact[Redaction and size limits]\n    redact --> memory[Ledger search]\n    memory --> manager[Model manager]\n    manager --> ollama[Loopback Ollama]\n    manager --> rules[Rule-based reader]\n    ollama --> parser[Pydantic parser]\n    parser --> ui\n    rules --> ui\n    ui --> policy[Command policy]\n    policy --> runner[Argument-list process]\n    ui --> ledger[(SQLite ledger)]\n```\n\nThe 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.\n\n```\nif exc.code == 500 and isinstance(body.get(\"format\"), dict):\n    try:\n        return self._request(\"POST\", \"/api/chat\", body=body, timeout=timeout)\n    except urllib.error.HTTPError as second:\n        exc = second\nif exc.code in {400, 500} and isinstance(body.get(\"format\"), dict):\n    relaxed = dict(body)\n    relaxed[\"format\"] = \"json\"\n```\n\nMemory 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.\n\n```\nanalysis.memory_incident_ids = [item.incident_id for item in matches]\nnote += \" A previous fix is not assumed to resolve this incident.\"\n```\n\nCommands 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.\n\nThe 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.\n\nThe project is built around that call, with the ledger in front of it:\n\nA 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.\n\nAn open-weight model behind Ollama changes the shape of the tool:\n\n`gemma3:4b`.\nOpen 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.\n\nI 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.\n\nThe moment that landed was not a jump scare. It was the second lantern failure.\n\nThe 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.\n\nThat is the haunting I wanted. The machine remembers the trace. It does not get to finish the ritual.\n\nGemma is the model the app is set up to call, and `gemma3:4b` through local Ollama produced a validated investigation on this machine.", "url": "https://wpnews.pro/news/ghostshell-the-terminal-remembers-the-bug-and-it-does-not-press-the-keys", "canonical_source": "https://dev.to/abishethvarman/ghostshell-the-terminal-remembers-the-bug-and-it-does-not-press-the-keys-51dn", "published_at": "2026-10-27 22:58:04+00:00", "updated_at": "2026-10-27 23:11:50.082889+00:00", "lang": "en", "topics": ["ai-tools", "ai-agents", "developer-tools", "ai-safety", "artificial-intelligence"], "entities": ["GhostShell", "Abishethvarman", "Ollama", "gemma3:4b", "Hacktoberfest", "Textual", "SQLite", "GitHub"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/ghostshell-the-terminal-remembers-the-bug-and-it-does-not-press-the-keys", "markdown": "https://wpnews.pro/news/ghostshell-the-terminal-remembers-the-bug-and-it-does-not-press-the-keys.md", "text": "https://wpnews.pro/news/ghostshell-the-terminal-remembers-the-bug-and-it-does-not-press-the-keys.txt", "jsonld": "https://wpnews.pro/news/ghostshell-the-terminal-remembers-the-bug-and-it-does-not-press-the-keys.jsonld"}}