Umwelt 0.1 · open source

What happened,
and who knows it.

An epistemic state engine that tracks what each character knows, and how they learned it.

Umwelt: the world as each being perceives it. The m and the w are the same form, seen from each side.
Why it exists

Stories leak.

Somewhere, someone knows more than they should. Here is where it usually happens, and what changes with a record of who knows what.

A model

withoutA model is told everything, then asked to pretend it doesn’t know. It leaks the twist.

with UmweltA model gets only what its character holds. The twist was never in the prompt.

A game

withoutA game decides who knows what with a pile of flags nobody can explain.

with UmweltA game asks one question: does this character hold it, at this point?

A long story

withoutA long story contradicts itself. Chapter 31 forgets what chapter 6 said, and who was in the room.

with UmweltA long story can ask what anyone knew, at any point, and how they learned it.

What it is

Your story knows everything. Your characters shouldn’t.

Umwelt keeps what happened in a world apart from what each character knows, believes or remembers: where they learned it, and since when. Then it answers from anyone’s point of view, at any moment.

No character knows too much.A model, a game or a writer only ever gets what that character holds.
Every piece of knowledge has a source.Who saw it, who said it, and when. Honest or not.
Wrong beliefs stay wrong.They are kept and flagged, never quietly fixed.
Use it

Wherever stories are kept.

Four places the same question comes up. What the records say, in plain words, and the exact request and response behind it. With a model or without one, the records are the same.

The situation

Session 12. The rogue overheard the king’s plan. The paladin was outside.

You ask

“Does the paladin know the plan?”

What the records say

There is no record of the paladin holding it. Only the rogue has one, from session 12.

Request
umwelt call campaign.umw holds '{
  "projectId": "west-marches",
  "holder": "paladin",
  "claim": { "subject": "king", "predicate": "plans",
             "object": { "kind": "entity", "id": "the-coup" }, "polarity": true },
  "at": { "tick": 12 }
}'
Response
{ "holds": false }
The situation

Chapter 31. The father mentions his daughter’s letter.

You ask

“Could he know about the letter yet?”

What the records say

His record of the letter starts in chapter 34. At 31 it is still in his future: the line is an anachronism.

Request
umwelt call novel.umw check.utterance '{
  "projectId": "saga",
  "holder": "father",
  "at": { "tick": 31 },
  "claims": [{ "subject": "daughter", "predicate": "wrote",
               "object": { "kind": "entity", "id": "letter" }, "polarity": true }]
}'
Response
{
  "consistent": false,
  "items": [{ "verdict": "future", "recordId": "father-reads-letter" }]
}
The situation

The guard is about to greet the player.

You ask

“Has the guard heard about the theft?”

What the records say

He holds a record of it: the innkeeper told him this morning. The game picks the suspicious line.

Request
umwelt call save.umw holds '{
  "projectId": "save",
  "holder": "guard",
  "claim": { "subject": "player", "predicate": "stole",
             "object": { "kind": "entity", "id": "ring" }, "polarity": true },
  "at": { "tick": 420 }
}'
Response
{
  "holds": true,
  "attitude": "knows",
  "confidence": 1.0,
  "polarity": true,
  "recordId": "guard-told-by-innkeeper"
}
The situation

A model is about to voice the butler.

You ask

“What can the butler’s prompt include?”

1

Your app asks Umwelt

What may the butler know right now?

umwelt call manor.umw context.admit '{
  "projectId": "manor",
  "holder": "butler",
  "candidates": [
    { "id": "guests", "recordId": "butler-saw-guests" },
    { "id": "cook",   "recordId": "butler-saw-cook" },
    { "id": "twist",  "recordId": "heir-poisoned-wine" }
  ]
}'
2

Umwelt answers

Two records go in. The twist stays out, with its reason.

{
  "admitted": [{ "id": "guests" }, { "id": "cook" }],
  "rejected": [{ "id": "twist", "reason": "not-held" }],
  "usedBudget": 2
}
3

Your app builds the prompt

Only the admitted records reach the model.

system

You are the butler of the manor. Answer in character.

he knows

The guests arrived at eight.
The cook was nervous all evening.

4

The model replies

In character, and without the twist it was never given.

the guest asks

“Did anything odd happen tonight?”

example reply

“Nothing out of the ordinary, sir. The guests arrived at eight, as expected. Though Cook did seem rather on edge all evening.”

Umwelt never writes the reply. It decides what the model is allowed to know; the model is yours.

Get started

Three steps to the first answer.

From an empty file to “who knows what”, in a few commands. The same scene works from TypeScript, .NET or any language.

1

Create a world

One portable file and one manifest: the project, its types, the people in it and what can be said.

umwelt create story.umw
umwelt call story.umw world.ensure '{
  "project": {
    "id": "ball",
    "name": "The Ball",
    "timescale": "scene"
  },
  "entityTypes": [ person, thing ],
  "entities": [
    ana, bob, duchess, necklace
  ],
  "predicates": [ stole ]
}'
{
  "created": {
    "project": true,
    "entities": [
      "ana", "bob", "duchess", "necklace"
    ],
    ...
  }
}
Send it again and nothing changes: it creates only what is missing.
2

Record what happened

One commit: the event, the Fact, and what Ana and Bob hold. The duchess gets nothing.

umwelt call story.umw commit '{
  "projectId": "ball",
  "attemptId": "scene-1",
  "event": { "id": "scene-1", ... },
  "records": [ theft, anaSaw, bobDid ]
}'
{
  "eventId": "scene-1",
  "recordIds": [
    "theft", "ana-saw", "bob-did"
  ],
  "version": 1,
  ...
}
Abridged: the full payload is in the guide.
3

Ask who knows

From anyone’s point of view.

umwelt call story.umw holds '{
  "projectId": "ball",
  "holder": "ana",
  "claim": { ...the theft }
}'
"ana"      →  { "holds": true,
                "attitude": "knows",
                "recordId": "ana-saw" }
"bob"      →  { "holds": true,
                "recordId": "bob-did" }
"duchess"  →  { "holds": false }
The duchess was at the ball, but nothing says she saw it.
Install
$npm install @kallamo/umwelt
$dotnet add package Kallamo.Umwelt
$cargo install --git https://github.com/Kallamo/Umwelt umwelt-cli
$umwelt serve world.umw
Built to be trusted

Small to adopt. Hard to break.

One file

A world lives in one portable .umw file. It can hold several isolated projects.

Any language

A Rust engine behind one JSON protocol: the CLI, TypeScript, .NET, the C ABI, or anything that speaks it.

Guarantees, written down

Confirmed history is never deleted. Beliefs are never corrected. Nothing is inferred. Each rule is in the spec.

The same everywhere

Every client passes the same conformance cases. A retried write with the same attempt id applies once.

Fast enough for a game

Asking whether a character knows something takes about 60 µs, with half a million Holdings, on a laptop.

See the numbers
License

Open source by default. Commercial when you need it.

And if you make something to play, you keep your code too.

AGPL-3.0-only

Open source

Use, study, change and share Umwelt freely. If you distribute your project, or let people use it over a network, its source goes out under the AGPL too.

  • Private and internal use: nothing to do
  • Open-source projects under the AGPL
  • Free games and play tools, with the Free Play Exception
Read the license
Commercial license

For products and services

Shipping a closed-source product, or offering Umwelt’s capabilities as a hosted service? A commercial license lets you build on Umwelt without the AGPL’s obligations.

  • Closed-source apps and games
  • Hosted services and APIs
  • Terms that fit your project
See prices and tiers
Free Play Exception

Free games and play tools

Use Umwelt without opening your own code. All we ask is a line of credit.

GamesModsInteractive fictionTabletop tools
Read the Free Play Exception
Still free with

Donations, pay what you want from zero, crowdfunding with thank-you rewards, game jams and prizes.

Not covered

A price above zero, in-game purchases or ads, paid content or early access, hosted AI services.

Kallamo is its biggest demonstration.

Umwelt is an idea long in the making. It grew up alongside Kallamo, a free, open-source and privacy-first app for telling stories with the AI of your choice, where every character knows only what reached them.

RoleplayWriting DeskWorldbuild
  • You choose the AI: a provider you trust, or a model on your own computer.
  • It writes only when you ask it to.
  • Your stories stay with you.
Meet Kallamo
Show us

Built something with it?

Share your game, mod, tool or story, and we may feature it right here. Or just come by: see what others are building, ask questions and talk about it with Kallamo’s community on Discord.

Your game here
Your mod here
Your tool here
Your story here
Questions

Before you start.

The questions people ask first. The full FAQ goes deeper, with a link to every page it mentions.

All questions
Is Umwelt a database?

It is an engine that keeps its state in one SQLite file. You record what happened and who knows it, then ask; you never write SQL. Read more

Do I need AI to use it?

No. Umwelt never runs or calls a model. Games, novels and tabletop tools use it as it is; with a model, it decides what may enter the prompt. Read more

How is it different from a vector database or RAG?

Retrieval finds what looks relevant. Umwelt answers who knows it and since when, and refuses what a character never learned, however well it matches. Read more

Can I use it in my game?

Free games, mods and tabletop tools that make no money can, without releasing their code, by crediting Umwelt. Commercial projects can get a license. Read more

Is it fast enough for a game?

Asking whether a character knows something takes 55 to 65 µs, in a file with half a million Holdings, on a laptop. Read more

Which languages can use it?

TypeScript, .NET, the command line, and anything that can speak its JSON protocol or load its C library. Read more