Guides / Use cases

Game NPCs

Characters that remember the player across play sessions, each from their own point of view: the blacksmith remembers the hammer you lost, the innkeeper only knows what reached his ears. Recall stores the scenes, learns what each NPC saw, and hands your dialogue model the right memory in a few hundred milliseconds.

What memory adds

Without memory, every conversation with an NPC starts from the script. With it, what the player did and said becomes part of the world:

Without memoryWith Recall
Day 3, at the forgeThe player loses Mira's hammer and promises her 30 gold by the harvest festival.
Day 9, back at the forge"Welcome, traveller! Need a blade?""Back again. The festival is in two days, and I still don't see thirty gold."
Day 9, at the innTomas has never heard of it.Only if your story let the rumour travel: Tomas knows what you told him, nothing more.

Recall does not write the lines. Your game's own model does, as it does now; Recall gives it what this NPC knows about this player, and learns from what was said.

How to model it

In your gameIn RecallWhy
A save game (or one player's world)Workspace, e.g. save-7f3aMemories of different saves never mix, and a new game is one delete.
The playerPeer playerRecall learns about the player from everything they say.
Each NPCPeer npc-mira, npc-tomas, with observeMe: falseYou write NPC personalities yourself, so Recall need not learn about them; their lines cost less.
A scene or conversationSession, e.g. forge-day-3The NPCs in a session are the ones who witnessed it.
What an NPC knowsThe NPC's view of the player: observeOthers: true in that NPC's sessionsMira's view is built only from scenes Mira was in.

Multiplayer works the same way: one peer per player, and each NPC keeps a separate view of each player it met. For a shared world, use one workspace per server or shard instead of per save.

Build it

Install the SDK (npm install @recall-memory/sdk or pip install recall-mem) and set RECALL_API_KEY. Create the save's peers and a session per scene; nothing is sent until the first call.

import { Recall } from "@recall-memory/sdk";

const recall = new Recall({ workspaceId: "save-7f3a" });

const player = recall.peer("player");
// Your game writes the NPCs' lines, so Recall need not learn about them (cheaper, see below).
const npc = { configuration: { observeMe: false } };
const mira = recall.peer("npc-mira", { ...npc, metadata: { role: "blacksmith" } });
const tomas = recall.peer("npc-tomas", { ...npc, metadata: { role: "innkeeper" } });

// One session per scene. Mira takes part and keeps her own view of the player.
const forge = recall.session("forge-day-3", {
  peers: [player, [mira, { observeOthers: true }]],
});

Every line of dialogue: one request. turn stores the player's line and returns the context for the reply in the same round trip: the scene so far, a summary of older turns, and what Mira has learned about the player. peerPerspective is what keeps her view her own. It uses no model, so it is fast and included in the price.

// One request per line of dialogue: store the player's line, get back what Mira knows.
const { context } = await forge.turn(
  [
    player.message(
      "I lost your hammer in the river. I'll pay you 30 gold by the harvest festival.",
    ),
  ],
  { peerTarget: player, peerPerspective: mira, tokens: 2000 },
);
const prompt = context.toOpenAI(mira); // Mira's memory as system messages, then the scene
// Your game's own model writes Mira's line from `prompt`; store it so she remembers saying it.
const line = "Thirty gold by the festival, then. I'll hold you to that.";
await forge.addMessages([mira.message(line)]);

Game logic: ask. For decisions (does Mira refuse to sell? does the debt quest unlock?), ask the NPC's memory in plain language. That is one model call of a few seconds, so call it when a quest step or a scene starts, not every frame. Ask for JSON with responseFormat when your code needs a field rather than a sentence.

// Quest logic, not dialogue: what does Mira believe? One model call, so keep it off the
// frame loop. (waitForIdle is for this demo; a game asks later, when learning is done.)
await recall.waitForIdle();
const debt = await mira.chat("Does the player owe me anything? How much, and by when?", {
  target: player,
  reasoningLevel: "minimal",
});

Rumours spread when your story says so. NPCs who were not there know nothing. To pass news on, write a fact into the listener's view yourself. That keeps gossip under your control instead of leaking between characters.

// Tomas was not at the forge, so he knows nothing yet. When your story says the news has
// travelled, write it into his view of the player yourself.
await tomas
  .conclusionsOf(player)
  .create("Heard from Mira: the player lost her hammer and owes her 30 gold.");
const rumour = await tomas.chat("What have I heard about the player?", {
  target: player,
  reasoningLevel: "minimal",
});

New game, or a player who leaves.

// A new game drops the whole save: its scenes first, then the workspace.
const scenes = [];
for await (const scene of await recall.sessions()) scenes.push(scene);
for (const scene of scenes) await scene.delete();
await recall.deleteWorkspace();
// To forget one player and keep the world: await player.delete()

Unity, Unreal and Godot

There is no engine SDK; the REST API is two calls. Do not put your API key in the game build, where players can extract it: call Recall from your game server, or mint each player a key scoped to their own save with POST /v3/keys, so a leaked key reaches no one else's memory (set a monthly cap under Billing too). The turn call from C#:

// POST /v3/workspaces/{save}/sessions/{scene}/turn
var body = @"{
  ""messages"": [{ ""peer_id"": ""player"", ""content"": ""I lost your hammer in the river."" }],
  ""context"": { ""tokens"": 2000, ""peer_target"": ""player"", ""peer_perspective"": ""npc-mira"" }
}";
using var req = new HttpRequestMessage(HttpMethod.Post,
    $"https://api.recallmem.dev/v3/workspaces/{save}/sessions/{scene}/turn");
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
req.Content = new StringContent(body, Encoding.UTF8, "application/json");
var res = await http.SendAsync(req);   // { "messages": [...], "context": { ... } }

Set up each scene once, before its first turn: POST /v3/workspaces/{save}/sessions with {"id": "forge-day-3", "peers": {"player": {}, "npc-mira": {"observe_others": true}}}. It is get-or-create, so sending it again is harmless. See the REST API.

Settings that matter

SettingUse
observeOthers: true per NPC, per sessionThe NPC builds its own view of the others in that scene. Leave it off for NPCs who should not remember.
peerPerspectiveRead the player through that NPC's eyes. Without it you get Recall's overall view of the player, which includes things the NPC never saw.
observeMe: false on NPCsRecall does not learn about the NPC from its own lines. Use it whenever your game, not the conversation, defines who the NPC is.
tokensThe context budget for the dialogue model, 1,000 to 4,000 is plenty for a scene. Older turns become a summary.
reasoningLevel: "minimal"For game logic questions: the cheapest and fastest level. See Reasoning levels and models.
Message createdAtRecall dates what it learns by when a message was written. If your world has its own clock, map game days onto dates and pass them, so "by the festival" is reckoned in game time.

Cost and speed

Measured from Europe against the hosted API (Frankfurt), October 2026: a turn or context call took 0.3 to 0.7 seconds, a question at minimal or low 2 to 4.5 seconds. Learning happens in the background and does not hold up the call.

Context, search and storage are included. You pay for learning, $1.75 per million message tokens with every message counting as at least 50, and for questions. A player who plays two hours a week, with 200 lines of their own and 200 NPC lines of about 30 tokens, and 20 game-logic questions:

ItemPer week
Player lines: 200 × 50 tokens × $1.75 / 1M$0.0175
NPC lines, read but not learned from: 200 × 30 tokens × $1.75 / 1M$0.0105
Questions at minimal: 20 × $0.0008$0.0160
Totalabout $0.04, or $0.18 a month

More in Cost and speed.

Privacy and forgetting

Players type freely into chat-driven games, including things that are not about the game. Say in your privacy notice that conversations with characters are stored to give them memory, and let players reset it. Deleting the save's workspace removes everything in it; player.delete() forgets one player in a shared world, including every NPC's view of them. Games for children need more care: see Privacy, consent and forgetting.

Pitfalls

Next: Cost and speed · Designing workspaces, peers and sessions