English | 日本語
Outcasts Lorekeel — a GM that never forgets or contradicts
A TRPG game master with a cloud LLM as narrator and a deterministic Rust engine as the source of truth for game state.
The failure mode that always breaks AI Dungeon–style LLM GMs isn't weak prose — it's forgetting and contradiction (what you carry, who died, where you are, what was decided last turn). Lorekeel cuts that off structurally: the LLM never holds the state. What it sells is not "infinite freedom" but consistency.
A side effect of that architecture: because the engine guarantees correctness, Lorekeel runs well on cheap, free, or fully local models. The engine backs up a small model's mistakes, so you don't need a frontier model to get a coherent game — only richer prose.

A scenario package in play — the GM's narration over a scene background, with live goals and the characters present in the scene on the right. Everything is driven by the deterministic engine underneath.
Download
Get the installer for your OS from the latest release.
| OS | File | Status |
|---|
| Windows | Lorekeel_x.y.z_x64-setup.exe (installer) / .msi / winget | ✅ Verified working |
| macOS (Apple Silicon) | .dmg / Homebrew | ✅ Signed, notarized, and launched on a real Mac (v0.5.17) |
| Linux | .deb / .AppImage / .rpm | CI build only, unverified |
On Windows you can install it with winget instead:
winget install Outcasts.Lorekeel
winget installs the .msi for all users, so Windows asks for administrator permission.
winget upgrade Outcasts.Lorekeel updates it. A new release reaches winget only after its
manifest is merged into winget-pkgs, so winget can lag behind the Releases page.
If you installed with the -setup.exe before, uninstall that copy first — the two installers
do not replace each other, and you would end up with two copies sharing the same data.
winget uninstall Outcasts.Lorekeel leaves your saves, packages and API keys in place
(see PRIVACY.md to remove them).
On macOS you can install it with Homebrew instead:
brew install --cask betyourluck/tap/lorekeel
The fully qualified name is not optional — tapping a repository does not grant Homebrew
permission to load code from it. Apple Silicon only; there is no Intel build.
brew uninstall --cask lorekeel leaves your saves, packages and API keys in place
(--zap deletes those too).
After launching, go to Settings → AI Model and set the base_url / model / api_key for an OpenAI-compatible endpoint (a cloud LLM, or a local OpenAI-compatible server). Play scenario packages by adding a folder or fetching them from the distribution site.
Design core — separation of powers
> The LLM proposes, the engine adjudicates, Memoria remembers, the scenario constrains.
| Branch | Role | Implementation | Status |
|---|
| Engine (source of truth) | Deterministically adjudicates every mutable state — HP/stats, inventory, dice, flags, location, skills, attributes | crates/gm_core (Rust) | ✅ Done |
| LLM (proposal) | Narration, NPC lines, action proposals. Holds no numeric truth (structurally can't) | crates/llm_client (Rust) | ✅ Done — 4 wire formats (OpenAI-compatible / Anthropic / Gemini / OpenAI Responses) |
| Memoria (memory) | Semantic recall of foreshadowing & character personality (never mutable state) | crates/harness (memoria_bridge) | ✅ Done |
| Scenario (constraint) | A location graph + gate conditions keep improvisation on the rails | YAML packages | ✅ Done |
Iron rule: mutable world state lives in the engine's state machine. It is never placed in vector recall — fuzzy recall would recreate the "forgetting GM." Only foreshadowing and personality belong to Memoria.
What the engine guarantees
The LLM proposes a StateDelta (structured output: narration + ops). The engine's adjudicate — a pure function that changes no state — verifies every op; on an illegal op it rejects with a machine-readable reason and the loop regenerates. Only on acceptance does apply mutate state, atomically (one bad op rejects the whole delta; state stays intact).
Because of that boundary:
- Numbers are the engine's. The LLM states the intent ("train hard: +STR, −HP"); the engine does the arithmetic. It cannot fabricate a die roll, an HP value, or an item it doesn't hold — the op structure makes it impossible.
- Dice are deterministic & auditable (seeded RNG). Same seed → same rolls.
- Closed world. Undeclared stats / items / skills / flags don't exist; the engine rejects any op that touches them. Skills, character classes, and who-is-present change only through authored triggers, never LLM whim.
- Consequence is authored. Named goals, campaign transitions (state carries across modules), challenges (dice → tiers → flags), delayed events, and hidden roles + voting (werewolf-style) are all gated by the engine, not the prose.
- Long memory. A running chronicle and compressed chapter synopses feed the GM its own past, so it stays consistent across long sessions — the second half of "never forgets."
Proven with real LLMs, across genres
The same unchanged engine drives fantasy dungeons, dating-sim routes (raising a heroine's affection), mystery, and social deduction (a hidden-werewolf village). The engine is genre-neutral; the LLM supplies the flavor. Verified end-to-end with Claude, Gemini, Grok, OpenAI, Meta, and Perplexity (Agent API via /v1/responses), and with local OpenAI-compatible servers via a no-tools JSON mode (for models that don't support tool calling). Prompt caching (Anthropic cache_control / Gemini cachedContent / xAI sticky routing) keeps the repeated input cheap.
The signature demonstration: tell the GM you use a "prophecy skill you never had," and it grounds the lie away — "there was never such a power" — with zero state change. The source of truth beats the LLM's fluency.
Authoring & distribution
Scenarios ship as self-contained packages — a folder with package.yaml + characters + scenarios (+ optional campaign, images, audio). Zip it, unzip it, it runs. A companion distribution site (the 書庫) lets authors share packages and players install them from inside the app. You can even build a package by handing an LLM the format spec and a synopsis; see the authoring guide.
Build & test
cargo test --workspace # 250+ deterministic PoC tests (Red→Green)
cargo clippy --workspace --all-targets
The desktop app (Tauri 2 + Vue 3) lives in app/:
cd app && npm install && npm run tauri dev # requires WebView2 on Windows
Layout
Lorekeel/
├── data_contract.yaml # ★ Frozen nouns (the GameState / StateDelta / Gate / Scenario contract)
├── crates/
│ ├── gm_core/ # Source of truth: state, scenario spine, adjudicate/apply engine
│ ├── llm_client/ # Narrator leg: 4-wire unified tool layer, schemars-generated schema,
│ │ # prompt caching, no-tools JSON fallback for cheap/local models
│ └── harness/ # Turn loop, memoria_bridge, synopsis/chronicle (long-term memory), campaigns
├── app/ # Tauri 2 + Vue 3 desktop app (save/load, immersion assets, i18n ja/en, 書庫)
├── packages/ # Distributable scenario packages
├── specs/ # Design specs (NN_*.md)
└── CLAUDE.md # Project ledger (architecture, north star, mandates)
Privacy
Lorekeel collects no telemetry. API keys are stored in your OS credential store, and game content is sent only to the AI provider you configure. See PRIVACY.md for what is stored, what is sent, and how to delete it.
License
MIT License. The engine and the bundled scenarios can be freely used, modified, and redistributed. It's worth something only when it's used — fork it and build your own world.