Introduction
Umwelt records what happened in a world and, kept apart from it, what each character knows, believes, suspects or remembers about it: from whom they learned it, at which point of the story, and whether it is still true. Every question is answered from a position and for a perspective, so “what did Ana know in chapter 6” is a query, not an act of memory.
It works entirely without AI, and it is built to keep AI characters honest: a model voicing Ana is given what Ana knows, never the twist she has not learned yet.
Status:
0.1, the first public release. The engine is complete and tested. The API may still change before1.0; every change to the file format comes with an automatic migration, so your files keep opening (see versioning).
What makes it different
- A fact is not knowledge of it. Canon about a character is not known by that character, or by anyone, until a record says so.
- Being in the room grants nothing. Who witnessed a scene, and how clearly, is recorded per character.
- Beliefs may be wrong, and stay held. A belief that contradicts canon is kept and reported, never silently corrected.
- Every piece of knowledge has a source. Who told whom, honestly or not, can be traced back link by link.
- History is never rewritten. Forgetting, revising and retracting are new records; every earlier state stays readable.
- Groups know their own things. What a guild knows is not the union of what its members know.
- Feelings are directional. What Ana feels toward Bob says nothing about what Bob feels toward Ana.
- Secrets are recorded, not enforced. Telling one to the wrong person is allowed, warned about and reported.
- Time can run on more than one clock. Story order and reading order live side by side: a flashback happens early and is read late.
- Work can wait for approval. A day of play or a generated scene waits in a draft timeline until it is promoted or discarded.
- Search stays inside the perspective. Full-text and semantic search, with vectors from your own embedding model, never surface what the reader may not know.
- Nothing is dropped silently. Every refusal, such as a memory left out of a model’s context, comes with a reason.
Quick start
| Install | Guide | |
|---|---|---|
| Command line | cargo install --git https://github.com/Kallamo/Umwelt umwelt-cli, or a release | getting-started |
| TypeScript / Node.js | npm install @kallamo/umwelt | getting-started, client guide |
| .NET 6+ | dotnet add package Kallamo.Umwelt | getting-started, binding guide |
| Any language | umwelt serve world.umw, JSON over stdio, or the C ABI | protocol |
import { createClient } from '@kallamo/umwelt';
const client = createClient({ file: 'story.umw', create: true });
// ... record a scene in which Ana sees Bob steal the necklace ...
const { holds } = await client.holds({ projectId: 'ball', holder: 'duchess', claim: theft });
// holds === false: the duchess was at the ball, but nothing says she saw itHow it works
CLI ──────────────┐
@kallamo/umwelt ──┤ JSON protocol v1
Kallamo.Umwelt ───┤ (stdio or C ABI) ──> engine (Rust) ──> world.umw (SQLite)
any language ─────┘Umwelt never runs or calls a model and never applies policy: how fast memories fade, whom a character trusts and which vectors to search with are the application’s decisions. The engine records them and reports what follows. The guarantees it keeps are listed in spec/invariants.md.