Kiori
Brains for characters. Kiori gives every character in your app a mind of its own: a past, a personality, people they love and resent, memories that fade or stay, and a strict sense of what they could possibly know.
You keep your chat, your model and your prompts. Kiori sits next to them:
your app ── record what happened ──▶ Kiori (organizer writes each character's memories)
◀── context for this turn ── (recall: no model call, ~free)
── check this draft ───────▶ (auditor: leaks, contradictions, invented past)
Why Kiori
- A real brain, not a prompt. Every character shares the Average Human Model (296 mechanisms of human psychology, 41 personality dimensions) and stores only the 1% that is theirs. Building a full brain costs about a cent and takes a minute and a half.
- Who knows what. In a story with many characters, each one learns only the scenes they were in. Secrets stay with the people who heard them. This is the part generic memory layers don't do.
- Memory that behaves like memory. What matters to them stays; what doesn't fades, then shrinks to its gist. Plans are remembered until they're done. A memory wipe is a memory wipe.
- Everything is proven. The organizer may only write what it can quote from the story. No quote, no memory.
- Nothing is a black box. Every memory is readable and editable, with the line of the story it came from. Export any brain to Obsidian.
- Rebuildable. Events are the source of truth. Improve the engine, rewind a story, fix a message: the brains are learned again from what happened.
Quickstart (5 minutes)
cd kiori # the Kiori folder
cp .env.example .env # put your OpenRouter (or any OpenAI-compatible) key in KIORI_LLM_KEY
node bin/kiori.mjs project create "My studio" # prints your API key once
node bin/kiori.mjs serve # http://127.0.0.1:7700 (console at /console, docs at /docs)
Then, in your app, one of these:
// The drop-in: your existing OpenAI-style chat call, sent through Kiori (it adds the mind, your model writes)
const ai = new OpenAI({ baseURL: 'http://127.0.0.1:7700/v1', apiKey: process.env.KIORI_API_KEY,
defaultHeaders: { 'X-Kiori-Upstream-Url': 'https://openrouter.ai/api/v1', 'X-Kiori-Upstream-Key': process.env.OPENROUTER_API_KEY } });
const reply = await ai.chat.completions.create({ model, messages }, { headers: { 'X-Kiori-Story': chat.id, 'X-Kiori-Characters': character.id } });
// Or one call per turn, for full control of your prompt
import { Kiori } from './sdk/kiori.mjs';
const kiori = new Kiori({ apiKey: process.env.KIORI_API_KEY });
// once per character, with your own id (a Tavern/SillyTavern card works too: character_card)
await kiori.characters.create({ external_id: 'char_mira', name: 'Mira',
description: 'A lighthouse keeper on a cold island who used to be a war medic. Dry humor, hates being pitied.' });
// every turn: your conversation id and your recent messages, as they are now (edits and rerolls handled)
const turn = await kiori.turn({ story: { external_id: chat.id, characters: ['char_mira'], player: { name: 'Leo' } }, messages });
const systemPrompt = `${yourCharacterPrompt}\n\n${turn.characters[0].text}`;
Python (sdk/kiori.py, no dependencies) has the same calls; any other language can use plain HTTP or generate a client from /openapi.json. Learning runs by itself as the story grows.
Learn more
- Concepts: the brain, stories and presence, organizer, auditor, sleep.
- Integration: the drop-in, one call per turn, or the building blocks; your ids, character cards, SDKs.
- API reference
- Self-hosting: configuration, models, costs.