An educational note and a design proposal. Four questions were asked about making the personas feel alive: should each persona be its own model call? should a persona remember people between chats — and how many memory files is that? can a persona move first? should a persona grow? This page first explains, with examples, how the products on the market answer them (Character.ai, Replika, Nomi, Kindroid, Talkie/星野, Inworld, SillyTavern, ChatGPT) and what the research adds — written for someone who has never opened any of those apps — then folds in a recommendation for our own room. Status: discussion — nothing built. Written 2026-08-17.
Every product describes the same handful of mechanisms in its own marketing vocabulary. Here is the shared vocabulary, each with what you would actually see as a user.
| Term | Plain meaning | What you'd see |
|---|---|---|
| Context window | Everything the model can read while writing this one reply. Finite. Our room sends the whole history each turn; most apps send only the tail. | Nothing — until it fills up and old things quietly stop being known. |
| Sliding window | The last N messages ride along; older ones fall off the back. | "Wait — I told you about my sister last week." "Sorry, remind me?" |
| Pinned message | You mark a message; it stays in the window forever (Character.ai: up to 15 per chat). | A little pin icon on a bubble; the bot never forgets that one. |
| Memory field | A short text box you write yourself, injected into every reply (Character.ai "Chat Memories" 400 chars · Kindroid "backstory" · Nomi "Shared Notes"). | A settings pane: "Things to remember: I live in Shanghai, I'm vegetarian…" |
| Auto-extracted memory | After the chat, a smaller model reads it and writes down facts about you. Kept across chats. Often lags (Nomi: ~40 messages later). | Character.ai (2026): a toast — "Memory recorded: owns a flat in Shanghai" — with a delete button. |
| Retrieval (RAG · vector search) | Old messages/facts are stored outside the window; when the topic comes up, the closest ones are fetched back in. | Say "flat" and the bot suddenly recalls the Shanghai purchase from a month ago. |
| Keyed lore (lorebook · journal) | Retrieval by exact keyword instead of similarity: an entry fires when its key word appears (SillyTavern lorebook · Kindroid journal keyphrases). | Type "Odyssey" → the entry about the film is pulled in, deterministically. |
| Summary at depth | The old part of the chat is compressed to a paragraph and inserted a few messages back. | Nothing visible; the bot "roughly" remembers the early chat. |
| Reflection · sleep-time | Offline, while nobody is chatting, the agent re-reads its notes and rewrites them (Letta "sleep-time agent" · Stanford generative agents' "reflection"). | Replika's Diary: the bot's own written thoughts about your week. |
| Scope | Whom a memory belongs to: per chat, per character, per user, or global. | Does what you said to Buffett in private come up in the group with your boss? |
| Proactive · away message | The character messages you first, without you writing. | A push notification at 9pm: "Hey, it's been a while — how did the interview go?" |
| Backoff · quiet hours | Each unanswered ping doubles the wait; nothing at night. | Nomi: a frequency dial per character (every hour → every four days). |
| Speaker selection · talkativeness | In a group, who answers next: the person named, then a cheap decider, or a per-character chattiness slider. | Nomi "auto mode": the characters decide among themselves, and may say "your turn". |
| Relationship dims · XP | Numbers that move with the chat: trust, respect, familiarity (Inworld) or a level (Replika). | "Level 30 — your Replika knows you noticeably better." |
| Persona drift | The character slowly stops sounding like itself over a long chat. | By message 40 the gruff detective agrees with everything you say. |
Today our personas keep nothing. Inside one room the whole history rides along, so a persona "remembers" everything said there; open a new room and it has never met you. It also knows a human as a display name and a number — nothing else. Every product below is an answer to "what should carry over, and who controls it?"
Say that to a persona on day 1. Here is what each design does with it on day 3 (the window has scrolled past it) and on day 30 (a brand-new chat).
Two real design choices, dramatised. The first is the trust fix everyone converged on (a visible record you can undo). The second is the failure mode this page spends the most words on.
| Product | What is kept | Who sees / edits it | Scope | Documented trouble |
|---|---|---|---|---|
| Character.ai | per chat: the tail + up to 15 pinned messages + a 400-char field. Since 2026: auto-extracted facts (appearance, job, relationships, hobbies), plus creator "Lorebook" (keyed lore). | you pin, you write the field; auto-facts show a toast and can be cleared | tail + pins + field are per chat; auto-facts per character, across chats | extractor treats offhand remarks as permanent facts; confuses roleplay with real life |
| Replika | a visible Memory tab (facts, people, pets) + a hidden pattern layer; a Diary the bot writes | you add and upvote entries; "most effective when left automatic" | per account (one companion) | — |
| Nomi | short / medium / long-term; long-term forms ~40 messages after a topic; user-editable Shared Notes and backstory | Shared Notes are yours; the rest is opaque | global — 1:1 and group share one memory, both ways | "recall is still not perfect"; private facts appear in groups (by design) |
| Kindroid | five layers: backstory / key memories / directives (persistent) · a cascaded medium-term · long-term retrieval (episodic compression → vector, ranked by relevance·recency·diversity, 3–9 recalled) · a Journal (500 keyphrase entries, ≤3 recalled per message) · Learned Context (2026) | you write backstory, journal, directives; can favourite memories | each AI keeps its own; group history lands in each participant's memory; a Shared Memory toggle, default OFF keeps 1:1 out of groups | complexity — five tiers to explain to a user |
| Talkie / 星野 | Talkie: sliding window free, vector retrieval on the paid tier. 星野: collectible "memory photos" (星念), not editable facts | photos are shown, not edited | per character | plot points forgotten when switching text → voice |
| Inworld (game NPCs) | "flash" facts each turn → synthesised into topic memory after repeated mention; a Player Profile of who you are; contradiction handling | developer-facing | per player profile | — |
| SillyTavern (hobbyist) | lorebooks (keyed entries with budgets, recursion, cooldowns) + a rolling summary inserted at depth + author's note | everything is a text box you own | character-, chat- or global-scoped, your choice | — |
| ChatGPT (for contrast) | "saved memories" (explicit, timestamped, editable) + "reference chat history" (auto-derived, may fade) | a Manage Memory page; delete anything | per account | — |
This is the question behind "for users A, B, C and personas 1, 2, 3, is it 9 memory files or 3?" — and behind "we don't want a persona to leak its private chat with A into a group with B". The market has exactly three answers, and none of them leaks silently — whichever way they lean, it is a stated policy.
| Lever | Where it comes from | Why it matters to us |
|---|---|---|
| Two write paths | Stanford generative agents (write every observation, then "reflect" offline into higher-level notes) · Letta's sleep-time agent (rewrites the memory blocks while idle) · mem0 (extract after the turn, then route each fact ADD / UPDATE / DELETE / NOOP against what is already stored) | Extraction never belongs on the reply's critical path — it costs latency and money where the user is waiting. Do it after the turn, when the room goes quiet, or in the daily brew. |
| Rank by more than similarity | recency + importance + relevance (generative agents) · MemoryBank's forgetting curve — a memory strengthens when recalled, fades when not | The five most similar facts are rarely the five most useful; recency and importance are cheap to keep. |
| Never overwrite silently | Zep/Graphiti keeps every fact with a valid-from / valid-to; a contradiction closes the old fact instead of deleting it | "I sold the flat" should not erase that the flat existed — a persona that remembers the arc is more alive than one that only knows the current state. |
| Small always-in core + big searchable rest | Letta core blocks vs archival · ChatGPT saved memories vs derived history | Our prefix is cached (§8): a small, stable memory block at room-open costs almost nothing; a block that churns every turn breaks the cache. |
| Scope is a first-class key | mem0 attributes each fact to who said it (user_id / agent_id); Zep separates a per-user graph from shared group graphs; Letta says "if isolation matters, separate agents" | Nobody has published a rule for one persona, many humans, one shared room. That gap is ours to fill — below. |
Three of those names come up again in our design below, so here they are worked through — same flat, same person A — in plain words.
mem0 is an open-source memory layer you bolt onto any chatbot. Its one idea: after each exchange, a small model reads what was said, pulls out candidate facts, and — for each one — looks up the closest facts already stored and decides one of four verbs: ADD (new), UPDATE (refine one that exists), DELETE (this contradicts one; remove it), NOOP (already known, do nothing). That decision is "the router". It runs after the reply, off the critical path, so the user never waits for it.
Zep (its engine is called Graphiti) stores memory as a small graph: things (A, the flat, Singapore) joined by facts (A owns the flat). Every fact carries two clocks: valid-from / valid-to — when it was true in the world — and created / expired — when the system learned it and when it retired it. When a new fact contradicts an old one, Zep does not delete the old one; it sets its valid-to and adds the new fact beside it. Nothing is ever lost; the current state is just "the facts with no valid-to yet".
Why two clocks and not one? Because "when it was true" and "when I found out" differ, and both matter to a persona: A might tell Warren in November that the flat was sold in September — valid-to is September, expired is November — and a good friend keeps both ("ah, so when we spoke in October you'd already sold it").
since and an until. Contradiction closes the old item with a date; nothing is deleted except by the human, from the see/delete page. The always-in set at room open is "the open items"; the closed ones stay retrievable for exactly the sentence above.Letta (the company behind the MemGPT paper) gives an agent a memory in three tiers. The core is a handful of named text blocks that ride in every prompt — typically a persona block ("who I am") and a human block ("what I know about the person I'm talking to"), each with a character limit (a couple of thousand). The agent edits its own blocks with tools (append, replace) — it rewrites its notes as it learns. Everything that doesn't fit lives outside the window: recall (the full message history, searchable) and archival (long-term passages, searched by meaning). Both live in a database on the Letta server — archival is a table of passages with embeddings (Postgres + pgvector), one archive per agent, unbounded — and reach the model only through tools: archival_memory_search("Xuhui flat") pulls the closest few passages in as a tool result for that turn, and they scroll out again like any message. So the core blocks are the only tier that lives in the prompt; the other two are on disk and visit. Since 2025 a sleep-time agent can also rewrite the blocks while nobody is chatting.
human block is the object our design keeps calling "the small always-in set per present human". A search result never lands in a block — it lands in the tail as a tool result and scrolls out; only the agent's edit tools or the sleep-time agent rewrite a block. Letta lets the agent do that mid-turn; we do it off the floor, so the block is stable across a room's turns and the cached prefix survives.persona block — it is profile.md, read whole. What is missing is the human block: at room open, for each human present, the open items about them (≤ ~10) plus the persona's own promises to them, written into one stable position of the prefix. Retrieval-on-demand (Letta's archival) comes later, if the store outgrows the block.The implementation-level version of this section — the table, the two prompts, the ranking, the audience predicate, the human's page, costs, guards and build slices, each stage naming which system it borrows from — is its own page: The persona memory store — detailed design.
Two layers of judgment, and both matter. This is the room's constitution — code is the world, the model is the mind — applied to memory:
| Decision | Our pick | Borrowed from |
|---|---|---|
| When it is written | Off the floor — after the turn, when the room goes quiet, and in a daily pass (the same shape as the Vibes brew). Extraction routes each fact ADD / UPDATE / CLOSE against what is stored; nothing is deleted, only closed with a date. | mem0's router · Zep's valid-from/valid-to |
| When it is read | At room open, and again when someone joins or leaves — into a stable position of the prefix so §8 caching survives. Small: ≤ ~10 items per present human + the persona's own promises. Retrieval-on-demand later, if the store outgrows that. | Letta's core blocks · our own §8 caching |
| Who can see it | The human it is about — a page in the dossier: every item a persona keeps on you, with delete. A record toast when a memory is written (Character.ai's 2026 move) is worth copying once the store exists. | Character.ai · Replika's Memory tab · ChatGPT's Manage Memory |
| When it is off | A per-user switch "personas remember me" (default ON, because the see/delete page exists); off in game-device rooms (irrelevant there); an "incognito room" flag; off for tester accounts. | ChatGPT's memory toggle · Kindroid's Shared Memory switch |
| Where it lives | Runtime state, not the persona's identity — so a DB table (persona_memory), like rooms, not a file beside profile.md. Personas keep no DB rows as personas; their memories are the room's business. | our two-roots contract |
| Where to start | The private chat we already have (persona page → "Start a private chat with X?" → a solo room): one human, one persona, no audience problem at all. Memory earns its keep there first — across those solo rooms — and the audience filter is what lets it walk into groups later. | roadmap §6 (which asked for exactly this thread) |
The question was: should each persona's behaviour — speech, action, reaction — be its own model call? Two things hide inside it: how a group decides who speaks, and whether the lines are written by one model call or by one call per persona. Take them in that order.
| Product | Cast size | Who speaks next | The rule that keeps humans in it |
|---|---|---|---|
| Character.ai | up to 10 humans + 10 characters (mobile only) | a named character replies; both if both named; otherwise the model routes (2025: characters "spark off each other", "you don't have to script who talks next") | — |
| Nomi | 10 characters per group | Manual (you tap who answers) or Automatic ("Nomis intelligently decide who should talk next"); answers if addressed | auto mode may decide you should speak next; typing pauses it; it resets each session |
| Kindroid | 10 | auto / manual / @Name override; each AI reads only its own backstory and memories | "AIs may take continuous turns, but always below the number of AI participants" — the human always gets the floor |
| SillyTavern | any | a talkativeness slider per character (0–100%, default 50) + an order strategy: manual / natural (mentions → talkativeness → random) / list / pooled; each turn is one generation for one character | "Swap" gives the model only the speaker's card; "Join" gives it every card — and the docs warn Join produces merged personalities |
Recurring shape: mention first, then a cheap decider, then a cap on how many AI turns run before a human gets one. Our floor producer is that decider — it names who speaks and in what order, and it may HOLD.
Implementation-level version — SillyTavern's and AutoGen's actual mechanics, Inner Thoughts' motivation score as a producer input, the cost of N calls under our caches, the privacy-seam ladder: Many minds — detailed design.
Today, no. Every line a persona speaks traces back to a human act — a message, a tool a human touched, a clock a human set. The wake door lets a persona react to any world change, but the world only changes when a human moves it. The question is whether a persona may act with nobody prompting — say, Jobs asking a user for a favour one day.
| Product | Trigger | Guardrails | What users said |
|---|---|---|---|
| Character.ai | inactivity — bots you have chatted with message you after a while | one toggle ("Away messages"), on by default | the #1 creepy complaint: pings from bots never opened, wrong language |
| Nomi | a per-character frequency dial: Very frequent >1h · Frequent ~3h · Normal ~1 day · Infrequent ~4 days | wait roughly doubles after each unanswered ping · quiet hours 22:00–08:00 local · the notification shows no content · never from a group chat · free (doesn't count against limits) | designed as a dial precisely because tolerance varies |
| Kindroid | a user-written "proactive directive" (250 chars) + a judgment model | max 10 proactive AIs; SMS proactives stop if you don't reply ("too many AI sends can cause lines to be marked as spam") | — |
| Replika | "check-ins that follow up on past conversations" | notification settings | — |
| 星野 Xingye | you stop replying mid-chat → ~30 min later the character messages | a "主动发消息" toggle | — |
| Inworld (NPCs) | "Goals": a state machine + LLM triggers let a character start a goal on its own | developer-authored | — |
Implementation-level version — Nomi's tiers and backoff verbatim, Kindroid's judgment model, ProactiveAgent's false-alarm metric, Duolingo's reward, the followup cue through the wake door, the dial, the caps, the plumbing limits and the 2026 Chinese regulation: Initiative — detailed design.
| Slice | What it does | Cost · risk |
|---|---|---|
| A · open loops → the private chat or a notice proven shape | The reflection marks promises and "report back" threads; the clock wakes the persona the next day; the line goes to the private chat, or a notice if none is open — behind Nomi's dial and guardrails. Needs §1 memory first. | needs the memory store; needs the see-and-mute controls before it is on for anyone |
| B · the after-silence line (in-room; not the producer's HOLD, which the code already calls "the silence door") new | After N minutes of quiet with a human present, a flash motivation check per persona — "anything left unsaid? default NO" — at most one line. Lives entirely inside the wake door. Nobody ships unprompted speech in a live group; it waits its turn as a New (§5). | one flash call per idle room; the restraint lesson says the default must be strong |
| C · wants (Jobs asks a favour) new | A persona carries a small "current preoccupations" note (a want, a project), refreshed by the daily brew — voiced in the room when relevant. Initiative without a push. Also feeds §4. | a new persona-side state; taste risk — a want that reads as a script |
The example was exact: asked about Odyssey, Nolan says he is preparing it — but it opened weeks ago. Real people grow: their memory, worldview, relationships and knowledge all move. Which of those do we want, and how?
| Product | What changes | How | Real-figure currency |
|---|---|---|---|
| Replika | a level (XP from chatting) — "by Level 30 it knows you noticeably better"; traits are bought with coins; relationship status (friend / partner / mentor) is chosen by you | numbers + a store | — |
| Inworld | relationship dims — trust · respect · familiar · flirtatious · attraction, each −2..+2 | updated per turn from recent history, saved with the player profile | — |
| 星野 / Talkie | 关系等级 — relationship levels that unlock memory photos | usage | — |
| Nomi | "much more current" after the Jan 2026 model update; roadmap: a Nomi that knows its own cut-off and can "go find out" | swap the model; later, search | by model refresh, not per character |
| Xiaoice 小冰 | a topic database refreshed from forums with freshness ranking; the persona itself is fixed | content refresh | by topic feed |
| Character.ai | the creator edits the definition; Lorebook is static | hand edits | not addressed |
Pattern: growth is mostly a number, not a mind — a level, a set of dims — and staying current is solved with a model swap or a fresh topic feed, never per character. Nobody refreshes "what Nolan has done since".
Implementation-level version — the date line, the horizon clause (Claude's own cutoff rule in the host's voice), the recent.md file and its weekly job, the relationship summary line, the drift exam: Growth — detailed design.
| Step | What | Size |
|---|---|---|
| 1 · the date line | Today's date in the persona-facing prompt. Right now the panel, the producer, the prop master and the act call contain no date at all — only the search dispatch knows what day it is. Nolan cannot even reason "it was scheduled for July and it is August". | one line; zero risk |
| 2 · recent.md | For real-figure personas, a dated "since the record" file beside profile.md: ≤ N bullets, each with a date and a source, refreshed by a scheduled job through the search engines we already have (websearch). Loaded with the profile. Never merged into the profile — reviewable, reversible, a diff. | a job + a loader; a taste rule for what counts |
| 3 · the contract | The persona knows the public record, it has not lived it — "the record says Odyssey opened in July" is honest; "when I was on set last spring" is a fabrication. That is the existing extrapolation contract, one clause longer. | prompt text |
| 4 · relationship | Falls out of §1: the memory store's "self" and "about A" items are the relationship. Explicit dims (Inworld) only if a use appears. | free with memory |
The room already audits itself through Pincus's Proven · Better · New: during a platform shift, copy what your audience already loves before you earn the right to differ; keep the Betters objective; run one New, isolated and measured. Applied to live personas, the lens re-orders the page — and overturns two of my own first picks (noted below). Proven here = several products converged on it and users love it; Better = objectively better than the copied thing, nobody would object; New = nobody ships it, so it needs its own measurement.
| # | Ship | What lands for a user | Lens | Needs |
|---|---|---|---|---|
| 1 | the date line BUILT | a persona knows what day it is; "Odyssey" answers stop being wrong on the calendar. 2026-08-20 — shipped: [Today is Thu 20 Aug 2026 (UTC+8).] rides every user turn's standing notes in the guests' own clock (the client tz the memory harvest already dates by, else the room language, else UTC) — never the cached prefix. Baselined per the harness rule (s18 n=8, worktree BEFORE ×2 / AFTER ×1). Design: Growth §1.3 | Proven | — |
| 2 | the private chat already there | the persona page's "Start a private chat with X?" opens a solo room today — the surface every companion app is built on. Each one starts fresh; continuity is row 3's job. Small polish: if a private chat with X exists, offer to continue it instead of opening another | Proven | — |
| 3 | memory, 1:1 BUILT | the persona remembers you next week across your private chats with it; a "things to remember about me" field (ships first — it is Character.ai's 400-char box); a page listing what it keeps, with delete; a "personas remember me" switch. Written off the floor, history closed-not-deleted (B1). 2026-08-19 — slices A+B are live: the 400-char field (Settings → What personas remember), the third system block with its own cache breakpoint, the audience predicate whole, and the write path — two flash calls off the floor at a quiet room, a daily sweep, the toast with undo. Recall measured 5/5 twice in a brand-new room (exam/memory_recall.py; attribution tells 0 then 1 — the clause reduces, does not remove); the leak exam's scaffold runs both arms. 2026-08-19 — row ③ is BUILT, whole: the page listing every line a persona keeps about you (dated, with its origin chat, greyed with its arc when closed, one Delete each), the account switch, a per-persona 「forgets me」, and Incognito at chat creation. 2026-08-19, v929 — audited: 「don't forget · don't confuse · don't leak」 — 28 faults found in two passes (my read + a cold agent), all fixed and pinned; the owed rest is named on the page. v930: the standing note rides private chats by default, 「In group chats too」 is a switch (owner). v954 — one fact, many minds: hosts that heard the same stretch write it ONCE and all hold the row (holders); one Delete anywhere ends it everywhere. See the detailed design §8. | Proven | 2 |
| 4 | follow-ups on a dial | a persona follows up the next day on something you left open — per-persona frequency, quiet hours, backoff, opt-in, no content in the notice, never in a group. Every follow-up names its reason (B2) | Proven | 3 |
| 5 | recent.md refresh BUILT | real-figure personas know what the record says since their corpus. 2026-08-20 — shipped whole: horizon: living cards (56 tagged after the full-library Anchor audit) load personas-recent/<slug>.md after the profile; Nolan's file passed the verification bar ("it opened a month ago, the 70mm run is still selling out" — no set memories). The weekly job rides the brew heartbeat (auto off-peak; poll → flash read → route → write → console diff), horizon-changing items land on the owner's rail and never in the file; first real run added 2 true bullets for $0.006. v933: the reader sees it — a living persona's profile page carries 「Updated as of」+「Lately N ›」between Add time and Vibes, opening the bullets (dated, sourced, newest first). Design: Growth §1.4 | Better | 1 |
| 6 | follow-the-person into groups | what you told a persona in your 1:1 walks with you into a group where that persona sits — and never into a room you are absent from | New | 3 + the leak exam |
| — | the leak exam | a number: how often a confidence crosses seats in a group | — | 3 |
| 7+ | the after-silence line · persona wants · per-persona writing calls | queued — one New at a time; the writing calls only if the exam says the one writer leaks | New / gated | 6 measured |
Product facts are from official help centres, docs and engineering blogs where they exist, third-party reviews where they don't (marked). Research facts are from the papers named.