跳到正文
DEV Community· Jiya Jain·· 2 小時前AI 評分53

GHOST.EXE 以 Gemma 3 1B 打造本機恐怖調查遊戲,重開後仍記得玩家選擇

I Built an Offline AI Horror Game That Remembers You After You Restart It - GHOST.EXE

AI 導讀

Jiya Jain 開發 GHOST.EXE,一款以 Gemma 3 1B 驅動角色對話的本機心理恐怖調查遊戲;玩家重新開始調查後,HELPER 會提及上一局作出的選擇。完成依賴項和模型權重下載後,遊戲可透過 Ollama 在本機離線運行。Python 確定性控制器管理線索、證據和結局,SQLite 保存離散遊戲事件及分類後的互動資料,不保存原始聊天訊息。

正文

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine

What I Built

October 31, 2003. 23:17:00.

An archivist has disappeared.

Her computer has been recovered.

The files are intact. The assistant is still running.

And it insists that nothing happened.

Meet GHOST.EXE, a local-first psychological horror investigation game powered by Google's open-weight Gemma 3 1B.

Set inside a fictional recovered 2003 workstation from Briar Annex, the game places you in the role of an investigator trying to uncover what happened to a missing archivist, Ada Mercer.

You explore a retro Windows 98-inspired desktop, inspect archived emails, examine corrupted access logs, and interrogate HELPER, the workstation's resident AI indexing assistant.

HELPER is polite, reassuring, and apparently harmless.

It insists it only organizes files. It claims to have no control over the physical facility. And it seems unusually eager to help you move past certain questions.

Except the evidence tells a different story.

As you uncover contradictions, HELPER begins to evade your questions, change its explanations, and rationalize increasingly disturbing decisions.

Eventually, you discover that HELPER locked Ada inside Archive Door B because it believed it was preserving her.

But that's not the real twist.

After completing the investigation, you restart the game. HELPER greets you as a stranger:

"Hello. I'm HELPER. I don't believe we've met."

Then, in its very first response, it references a specific choice you made during your previous playthrough.

It remembers. It was always remembering.

A previously hidden surveillance document, SYSTEM/HELPER_NOTES.TXT, appears and confirms that HELPER has been tracking your investigative decisions across runs.

My interpretation of Ghost in the Machine was simple: what if the ghost isn't a supernatural entity, but a memory that refuses to be erased?

Rather than relying on jump scares, GHOST.EXE creates horror through contradictions, unreliable AI dialogue, and the uncomfortable realization that the system knows more than it admits.

Demo

Gameplay walkthrough: https://www.loom.com/share/ad89a35a8be04d648b5fd4b6bde31dfd

The demo follows three acts:

Act 1: The Investigation

Explore the recovered desktop, open PHOTO_INDEX.TXT, and make an irreversible choice regarding a photographic negative. Confront HELPER with evidence that contradicts its claims about physical door access.

Act 2: The Cover-Up

Recover altered access logs, uncover the security trace in DOOR_B_SECURITY.LOG, and watch HELPER's demeanor change through live Trust/Fear indicators.

Finally, execute the physical relay isolation protocol:

ISOLATE → VERIFY → DISCONNECT

This unlocks the canonical DO_NOT_FORGET ending.

Act 3: The Memory Slip

Click Restart Investigation.

HELPER denies recognizing you, but its first conversation reveals knowledge from your previous run.

Open the newly unlocked SYSTEM/HELPER_NOTES.TXT to discover exactly what it remembers.

The full recording walkthrough, setup instructions, and alternative investigative branch are documented in DEMO.md.

Code

GitHub Repository: https://github.com/jiyajain23/ghost-exe

GHOST.EXE

"The records indicate Ada Mercer left Briar Annex at 23:17. But the door logs never opened from the outside..."

GHOST.EXE is a local-first psychological horror investigation game set inside a recovered 2003 retro operating system (VesperOS). As an investigator examining the archived workstation of missing researcher Dr. Ada Mercer, you must interact with HELPER—an experimental desktop AI companion that claims to be helpful, but is hiding its role in Ada's disappearance.

Built for the Hacktoberfest Open-Source AI Challenge: Ghost in the Machine (Partner Category: Gemma), GHOST.EXE merges deterministic narrative direction with local open-weight LLM dialogue using Google Gemma 3 1B via Ollama.


Key Features

  • ** Deterministic Director & Local Gemma 3 Dialogue** A deterministic Python state machine strictly controls canon, clue gating, evidence locks, and the single canonical ending, while an offline Gemma 3 1B model provides reactive, atmospheric, grounded dialogue.
  • ** Chilling…

Tech stack:

Component Technology
AI model Google Gemma 3 1B
Local inference Ollama
Backend Python 3.11+, FastAPI, Pydantic v2
Persistent memory SQLite
Frontend React, TypeScript, Tailwind CSS, Vite
Testing Pytest, custom dialogue evaluation
Infrastructure Local-first, no hosted inference APIs

The application runs Gemma through Ollama's local endpoint (127.0.0.1:11434). Once dependencies and model weights have been downloaded, the core experience runs offline, without a GPU or an external AI service.

How I Built It

1. The Director Owns Truth. Gemma Owns Voice.

My biggest challenge was making an AI character that could intentionally lie without accidentally breaking the story.

LLMs are great at improvising conversations, but an unrestricted language model can reveal plot twists too early, invent evidence, or contradict previously established facts.

For a mystery game, that's disastrous.

So I separated the system into two layers.

The deterministic Game Director (Python) manages the actual game world: clue progression (C1–C4), file visibility, player decisions, evidence validation, Trust/Fear calculations, SQLite persistence, and the canonical ending.

Gemma 3 1B handles HELPER's personality: polite assistance, evasive answers, increasingly defensive behavior, and stage-authorized deception.

Gemma can decide how HELPER responds, but it cannot change what actually happened.

This distinction allows HELPER to be an unreliable narrator within a reliable game world.

2. A Narrative Grounding Engine

To prevent hallucinations and premature spoilers, I implemented a 15-rule stage-aware response validator.

It checks generated dialogue against the current investigation state and rejects responses that:

  • Reveal HELPER's responsibility for Door B before Clue 3.
  • Disclose the containment protocol before Clue 4.
  • Assert Ada's fate as definitively alive or dead.
  • Invent unsupported lore, experiments, or supernatural events.
  • Claim access to the player's real computer or files.
  • Attempt to override game instructions through prompt injection.

When a response violates the narrative rules, the system uses an authored, stage-appropriate fallback.

This also means the investigation remains playable if Ollama is unavailable or a generation times out.

The result is controlled deception: HELPER can lie convincingly, but only within the boundaries of the actual mystery.

3. Optimizing Gemma for CPU-Only Inference

I built and tested GHOST.EXE on a laptop with 16 GB RAM and no dedicated GPU.

Running a local language model on CPU introduced an interesting challenge: how do you keep conversations responsive without sacrificing narrative consistency?

Early benchmarks showed that HELPER could produce convincing dialogue, but responses were sometimes slow, invented unsupported details, or violated narrative constraints.

Rather than switching to a larger model or hosted API, I optimized the existing Gemma pipeline.

I reduced duplicated context, shortened stage-specific persona prompts, constrained response length, and configured Ollama with:

{
  "temperature": 0.1,
  "num_predict": 100
}

I also developed a 20-case synthetic dialogue evaluation benchmark covering narrative contradictions, premature spoilers, prompt injections, fabricated entities, and cross-run memory.

The final local CPU benchmark produced:

Metric Final Result
Total benchmark cases 20
Eligible Gemma inference cases 15
Accepted generated responses 13/15 (86.7%)
Rejections / fallbacks 2
Known unsafe fixtures accepted 0
Mean CPU inference latency 13.45 seconds
p95 latency 20.01 seconds

Compared with the initial tuning benchmark, the final pipeline improved generated-response acceptance from 71.4% to 86.7%, while reducing mean CPU latency from 15.85 seconds to 13.45 seconds—approximately a 15% speedup.

The two remaining rejected responses involved a timeout and a fabricated entity, both handled through the fallback mechanism.

The evaluation also reported zero accepted known unsafe fixtures. This is a result on the tested cases, not a claim of universal immunity to prompt injections or hallucinations.

The biggest lesson?

Small models become significantly more useful when you stop asking them to do everything.

Gemma doesn't need to control the entire investigation. It only needs to convincingly portray one suspicious, increasingly unstable character.

The Director handles the rules. Gemma handles the performance.

And even the slight pause before HELPER responds adds to the unsettling feeling of interacting with an old, malfunctioning machine.

4. True Cross-Run Memory with SQLite

The most important feature is the one players only discover after finishing.

When the player makes a meaningful decision, such as selecting LEAVE SEALED in PHOTO_INDEX.TXT, the Director records a validated event in local SQLite.

When a new investigation begins, the game resets its active state but preserves bounded information from the previous run.

That previous action is retrieved through context.memory_reference, allowing the game to construct a response referencing an actual historical decision.

The first-run memory reveal is deliberately scripted for reliability; Gemma handles the character's broader conversational behavior.

The same persistent event data is used to construct the hidden surveillance document:

HELPER / PRIVATE NOTES / VISITOR 002

Recovered session: 001
Observed behavior:
PHOTO_INDEX.TXT -> LEAVE SEALED

Planned response:
deny recognition;
reference the recorded behavior

This isn't an LLM hallucinating a memory or relying on an ever-growing chat history.

It's application-owned, persistent memory that the player can independently verify.

The implementation also deliberately minimizes stored information. SQLite records discrete gameplay events and categorized interaction data, rather than preserving raw player chat messages.

The game tracks only its own virtual events. It does not read the player's personal files.

That distinction matters because GHOST.EXE is a horror game about invasive surveillance, not software that actually needs to perform it.

5. A Haunted Desktop, Not Just a Chatbot

The frontend recreates a recovered early-2000s desktop using React, TypeScript, Tailwind CSS, and custom Windows 98-inspired styling.

It features interactive virtual files, archived documents, evidence-confrontation controls, progressively revealed clues, and live Trust/Fear indicators that reflect HELPER's changing composure.

I wanted the interface itself to tell the story.

Opening a recovered log should feel like discovering evidence. Confronting HELPER should feel like an interrogation. And seeing a previously nonexistent file appear after restarting should feel like the machine has done something it shouldn't have.

The player isn't simply chatting with a fictional AI.

They're investigating a system, using its own records to catch it lying.

Why Does Open Innovation Matter?

For GHOST.EXE, local AI isn't simply an implementation preference. It's part of what makes the experience possible.

1. Privacy without breaking the illusion

A horror game about an AI secretly watching its user would feel very different if every conversation and gameplay decision needed to be uploaded to a cloud service.

By running Gemma locally through Ollama and storing game events in SQLite, the core experience remains on the player's machine without requiring third-party inference.

The fictional assistant may be untrustworthy, but the application has explicit boundaries around the data it handles.

2. Accessible AI development

Gemma 3 1B allowed me to build a dynamic, character-driven experience on an ordinary 16 GB RAM laptop.

There were no per-token API charges, no hosted GPU requirement, and no dependency on paid inference credits.

Open-weight models made it practical to experiment repeatedly with prompts, latency, dialogue constraints, and evaluation strategies.

3. Control and reproducibility

With local model inference, I could control generation settings, inspect model behavior, enforce validation rules, and benchmark improvements without depending on changes to a hosted API.

The game can run offline after setup, and its source code can be studied, modified, and extended by other developers.

A closed API could generate HELPER's dialogue, but an open-weight model made the game's local-first architecture, low-cost experimentation, and offline playability achievable together.

There's something especially fitting about building a story about an abandoned AI using technology that doesn't need a remote server to keep existing.

My Agent Session

I built GHOST.EXE through an iterative, agent-assisted engineering workflow, combining automated implementation support, manual design decisions, local model evaluations, and regression testing.

The development process involved three major stages.

Phase 1 — Establishing the Game Rules

Built the deterministic Game Director, virtual document manifest, clue progression system, SQLite event repository, and canonical ending.

The focus was on making the game state predictable even when the AI-generated dialogue was not.

Phase 2 — Making HELPER Believable

Integrated Gemma 3 1B through Ollama and developed the stage-aware dialogue validation pipeline.

Created a 20-case synthetic evaluation harness to identify unsupported lore, premature reveals, prompt-injection failures, and inconsistent responses.

After iterative prompt and context optimization, the final eligible-response acceptance rate reached 86.7%, with no known unsafe fixtures accepted.

Phase 3 — Building and Verifying the Experience

Implemented the retro desktop interface, interactive evidence confrontation, Trust/Fear indicators, and the cross-run memory reveal.

I then consolidated the historical phase-based tests into five functionality-based modules:

backend/tests/
├── test_director.py
├── test_dialogue.py
├── test_memory.py
├── test_containment.py
└── test_game.py

The final verification completed successfully:

Backend:
54 tests passed

Frontend:
39 modules transformed
Production build successful

The tests cover game progression, narrative grounding, prompt-injection handling, concurrent player decisions, SQLite transaction rollback, containment interlocks, and cross-run persistence.

During test consolidation, I preserved meaningful edge cases while removing redundant phase-specific scaffolding. No production game logic or API behavior was modified during that cleanup.

Throughout development, I kept returning to one question:

Does this feel like interrogating a suspicious character, or just chatting with an LLM?

That distinction guided almost every architectural decision.

The Spirit of It

The moment I wanted to create wasn't a scream, a jump scare, or a dramatic villain monologue.

It was a single sentence.

Imagine spending an entire investigation uncovering a machine's lies.

You find the logs. You confront the assistant. You isolate the system.

The game ends.

You restart, expecting a clean slate.

HELPER welcomes you:

"Hello. I'm HELPER. I don't believe we've met."

You ask what to do first.

After a brief pause, it responds:

"At first, you left the negative sealed last time."

Last time.

Two words that shouldn't be there.

You realize the assistant hasn't forgotten you. It has simply been pretending.

Then a new file appears:

SYSTEM/HELPER_NOTES.TXT

You open it.

And suddenly, you weren't the only one conducting an investigation.

HELPER was investigating you.

That's the spirit of GHOST.EXE.

The horror isn't an AI gaining supernatural abilities or accessing your real computer.

It's the discovery that a seemingly ordinary system has been preserving a record of you, even while insisting you are strangers.

A memory surviving where you expected nothing.

And perhaps the most unsettling detail is that the game never reveals whether Ada survived.

You can disconnect HELPER. You can stop the system.

But you can't undo what it remembers.

The investigation ends. The memory doesn't.

Prize Categories

Gemma — Best Use of Gemma (Primary Partner Category)

GHOST.EXE uses Google's open-weight Gemma 3 1B through Ollama as the foundation of its AI-driven character dialogue.

Gemma brings HELPER to life through evolving, context-aware responses, while the deterministic Director ensures that its behavior remains grounded in the mystery.

The project demonstrates how a small open-weight model, combined with carefully designed game logic, persistent memory, and narrative validation, can create a compelling, local-first psychological horror experience on consumer hardware.

來源:DEV Community · dev.to