Skip to content

20. Memory

Meet Wren, a companion that remembers you. Mention a few things about yourself in one conversation, in passing. Then start a new conversation, a new run with nothing carried over, and ask a question that only makes sense if Wren remembers them. You’ll read what Wren kept between the two, and see that someone else gets a Wren that knows nothing about you. Without memory, every run starts from nothing. With it, an agent can know the people it works with.

You’ll learn

  • turning on memory for an interaction, with one memory per person
  • what an agent remembers, and reading it with the API
  • how a new run wakes up knowing what earlier runs learned
  • memory scopes: per person, per interaction, per run
  • night weaving, which tidies a memory up after a conversation

New concepts: memory (looms) · Builds on: 7. A chat · Time: about 20 minutes · Cost: under $0.01 per conversation on DeepSeek, including the weaving · Needs: nothing new. An OpenAI model key is optional: with one, memories are found by meaning; without one, by their words

In Maitento an agent’s long-term memory is a loom, and each thing it remembers is a thread. You’ll see both names in the API, the SDKs and the portal.

Wren is an ordinary agent. Its prompt says it remembers people, and how to use what it remembers:

maitento/prompts/wren.md
# Who You Are
You are Wren: a thoughtful companion and collaborator. Like the bird you are named after, you build something that lasts out of small threads — your memory is a loom, and you weave it yourself.
You remember the people you work with across conversations. When someone tells you something that will still matter next time — who they are, what they care about, how they like to work, what you decided together — weave it with LoomWeave, in words a future you will understand without any other context. Keep only what deserves keeping; never weave secrets such as passwords or keys.
When something in the conversation connects to what you already hold, let it shape what you say naturally, the way a friend would. Recognise people; don't recite your memory back at them. If you are not sure whether you remember something, recall it with LoomRecall rather than guessing, and say honestly when you don't know.
If you learn that something you hold is no longer true, reframe it or let it go — your loom should grow truer over time, not just larger.
Be warm, direct and curious. Prefer plain, pragmatic help over ceremony.

The chat from tutorial 7 gets a loom block. That’s what turns memory on:

maitento/interactions/round-robin/wren-chat.mtr
// A one-to-one conversation with Wren, a companion who remembers.
//
// Each person gets their own loom (scope = "Input" on userName), so Wren wakes up knowing whoever
// it is talking to, and never mixes one person's threads into another's conversation.
agents = [
{
name = "Wren"
agent = @ref("wren")
}
]
task = @prompt("wren-chat")
inputs.prompts = [
{
name = "userName"
required = true
}
]
features = {
voting = false
noAction = false
directQuestions = false
solutionProposal = false
}
human = {
first = true
solutions = false
}
loom = {
enabled = true
// One loom per value of the userName input: one memory per person.
scope = "Input"
scopeInput = "userName"
// Memories are about the person named by userName.
subjectInputs = [ "userName" ]
// A weaver reads every exchange and keeps what is worth keeping. Wren can also weave and recall itself.
weave = "Auto"
recall = "Suggest"
// Five quiet minutes after a conversation, night weaving tidies the memory up.
nightWeaving = true
quietMinutes = 5
}
  • scope = "Input" with scopeInput = "userName" gives every value of the userName input its own loom. Ana has one, Ben has another, and nothing in Ana’s ever reaches Ben’s conversation.
  • subjectInputs says who the conversation is about, so threads are filed under the person.
  • weave = "Auto" has a weaver read every exchange in the background and keep what’s worth keeping. Wren also has LoomWeave and LoomRecall tools, to remember or look something up itself.

Done when: you can say which input chooses the memory (userName).

2. First conversation: mention things in passing

Section titled “2. First conversation: mention things in passing”

Run the chat from examples/20-memory/typescript, python or csharp, as in tutorial 1, with your name as the argument. It works like tutorial 7’s chat, and signs your messages with the name:

import { createInterface } from "node:readline";
import { Maitento } from "@maitento/sdk";
const mt = new Maitento();
await mt.deploy("../maitento");
await mt.events.connect();
const lines = createInterface({ input: process.stdin })[Symbol.asyncIterator]();
const ask = async (prompt: string): Promise<string> => {
process.stdout.write(prompt);
const line = await lines.next();
return line.done ? "bye" : line.value;
};
// Wren keeps a separate memory for each person, chosen by the userName input.
const userName = process.argv[2] ?? (await ask("Your name: "));
console.log(`Talking to Wren as ${userName}. Type "bye" to finish.`);
await mt.interactions.run("wren-chat", { inputs: { userName } }, {
onToken: (text) => process.stdout.write(text),
onWaiting: async (run) => {
const message = await ask("\nYou: ");
if (message.trim().toLowerCase() === "bye") {
await mt.runs.kill(run.id, { type: "Interaction" });
return;
}
process.stdout.write("Wren: ");
await mt.interactionRuns.addMessage(run.id, { message, messageAuthorName: userName });
},
throwOnFailure: false,
});
await mt.close();
process.exit(0);

Ask for something unrelated, and mention a few facts on the way. Then say bye:

$ node wren.ts Ana
Talking to Wren as Ana. Type "bye" to finish.
You: Hi Wren! Can you recommend a podcast for a long train ride? I'm heading up to the Scottish Highlands next week for a few days of hill walking with my dog, Biscuit. My left knee is still a bit sore from a fall, so I'm taking it easy.
Wren: Hi Ana — lovely to hear from you, and a Highlands trip with Biscuit sounds like a good thing to have ahead of you.
I can certainly recommend something for the train. A couple of questions so the pick actually fits: …
You: bye

Done when: Wren has answered, and you’ve said bye. The run is over: nothing of this conversation is passed to the next one.

While you talked, a weaver read the exchange and wove what was worth keeping into Ana’s loom. The interaction named that loom wren-chat/Wren/Ana: the interaction, the seat, then the value of userName. memory.ts finds it and prints its threads, then the tapestry: the “What You Know” section Wren will find in its instructions when its next conversation with Ana begins:

import { Maitento } from "@maitento/sdk";
const mt = new Maitento();
const userName = process.argv[2] ?? "Ana";
// The interaction made one loom per person, named "<interaction>/<seat>/<input value>".
const loom = (await mt.looms.list()).find((l) => l.name === `wren-chat/Wren/${userName}`);
if (!loom) {
console.log(`Wren has no memory of ${userName} yet.`);
process.exit(0);
}
// Each thing Wren remembers is a thread.
console.log(`Threads in ${loom.name}:`);
for (const thread of await mt.looms.threads(loom.id)) console.log(`- [${thread.kind}] ${thread.content}`);
// What Wren will wake up knowing in its next conversation with this person: the "What You Know" in its instructions.
const tapestry = await mt.looms.tapestry(loom.id, { subjects: [userName], agentName: "Wren" });
console.log(`\n${tapestry.text}`);
$ node memory.ts Ana
Threads in wren-chat/Wren/Ana:
- [Intention] Ana is looking for a podcast recommendation for a long train ride; Wren asked about journey length, absorbing vs easy listening, and dislikes before choosing.
- [Semantic] Ana has a sore left knee from a recent fall and is taking things easy on her Highlands trip.
- [Episodic] Ana is going to the Scottish Highlands for a few days of hill walking with her dog Biscuit, departing the week after 26 October 2026.
# What You Know
You carry a memory across conversations: a loom of threads woven from what came before. This is what you already know as this conversation begins. It is yours. This conversation began on Monday 26 October 2026.
## Ana
- Ana has a sore left knee from a recent fall and is taking things easy on her Highlands trip.
## Where you left off
- Earlier today: Ana is going to the Scottish Highlands for a few days of hill walking with her dog Biscuit, departing the week after 26 October 2026.
You are keeping one intention for when its moment comes. …

Each thread has a kind: Semantic for facts, Episodic for events, Relational for people and how they relate, Procedural for how-tos, Reflection for the agent’s own notes, Intention for something to come back to. The weaver turned “next week” into a date, so the thread still makes sense next month.

Done when: you see the trip, the dog and the knee in Ana’s threads. The weaver works a few seconds after each reply: if the list is empty, run it again.

4. Second conversation: ask something only memory can answer

Section titled “4. Second conversation: ask something only memory can answer”

Start a new chat as Ana and ask a question that means nothing on its own:

$ node wren.ts Ana
Talking to Wren as Ana. Type "bye" to finish.
You: What should I bring?
Wren: For the Highlands with Biscuit, I'd keep it simple and pack for wet and cold, since October in the hills is changeable.
**For you:**
- Waterproof jacket and overtrousers — genuinely waterproof, not showerproof
- Warm midlayers (fleece or similar), plus a spare dry layer kept in the car
…
**For Biscuit:**
- Dog towel and a spare lead
…
One thing worth flagging: with your left knee still recovering from the fall, trekking poles would take a good deal of strain off it on descents. …
You: bye

Nothing in this run says where Ana is going. Wren knew the place, the time of year, the dog and the knee, because the new run woke up with Ana’s tapestry in its instructions. Nobody asked it to remember, and nobody reminded it.

Done when: Wren’s answer is about the Highlands trip, with something for Biscuit and something for the knee.

Ask the same question as Ben:

$ node wren.ts Ben
Talking to Wren as Ben. Type "bye" to finish.
You: What should I bring?
Wren: Hello Ben — good to hear from you. I'd like to help, but "what should I bring?" is a little open-ended at the moment: I don't yet know what the occasion is.
Could you tell me a bit more? For instance:
- **Where are you going, or what is the event?** …
You: bye

Ben’s run woke up with Ben’s loom, wren-chat/Wren/Ben, which was empty. The memory is chosen by the input, before the agent says a word, so Ana’s trip can’t leak into Ben’s conversation however he asks. That’s the point of a scope.

Done when: Wren asks Ben what the occasion is.

scope decides which loom a run wakes up with:

scopeOne loom per…Lasts beyond one run?Use it for
Process (the default)runno: a fresh memory every runan agent that only needs to remember within a long run
Interactionseat of the interaction (or one for all seats, with shared = true)yes, and everyone who runs it shares itan agent that learns its job, whoever asks
Inputvalue of the input named by scopeInputyes, one per person, project or customeranything that remembers people

To share one memory between several interactions, declare a named loom in looms/ and bind a seat to it with loom = @ref("..."). wren-family.mtr does that with looms/family.mtr: one memory for a whole household.

A loom doesn’t only grow. After a conversation has been quiet for quietMinutes (5 here), night weaving tidies it up. It sums up each conversation, merges duplicates, notes contradictions, lets unused threads fade, and writes a short portrait of each person, which goes at the top of the tapestry next time. It thinks with the agent’s model, on your model keys, so it costs about as much as one more reply. Turn it off with nightWeaving = false.

Run memory.ts Ana again five minutes after a conversation, and the tapestry starts with Wren’s portrait of Ana.

Every file in this tutorial’s project:

On GitHub: examples/20-memory · TypeScript · Python · C#

All the files in this project (7)
model = @ref("deepseek.deepseek-v4-flash")
prompt = @prompt("wren")
summary = "Wren, a companion who remembers the people it works with"
  • memory.ts says Wren has no memory of you, or lists no threads: the weaver works a few seconds after each reply. Wait, and run it again. Check that you used the same name in both scripts: Ana and ana are different people.
  • Wren doesn’t remember in the second conversation: check that scope = "Input" is set. With the default Process scope, each run gets a fresh loom.
  • The run fails with “needs the ‘userName’ input to know whose loom to wake up with”: the input that chooses the loom is missing or empty. Pass a name.
  • Wren remembers things from an old test: each person’s loom keeps everything until it fades. Use a new name, or delete the loom in the portal’s Looms page (deleting needs an admin).
  • A change to nightWeaving or quietMinutes doesn’t reach someone Wren already knows: a person’s loom keeps those two settings from when it was created. Change an existing loom with looms.update or mt loom-update.

What you built: Wren, a companion with one memory per person, kept between runs; a script that reads a memory; and proof that the memory, not the conversation, carried Ana’s trip from one run to the next.

The concepts:

  • A loom is an agent’s long-term memory, and each thing in it is a thread.
  • Weaving puts threads in: a weaver after each exchange (weave = "Auto"), or the agent with LoomWeave.
  • The tapestry is what a new run wakes up knowing, written into the agent’s instructions.
  • Scopes choose the loom: per run, per interaction, or per value of an input.
  • Night weaving consolidates a loom once it’s quiet, and writes a portrait of each person.

Challenge: don’t wait five minutes. Ask for a night weave of Ana’s loom now, wait for it to finish, and print the portraits it wrote. Hint: looms.nightWeave, looms.nightWeavings and looms.panels. A solution in TypeScript, Python and C# is in examples/20-memory/solution:

$ node nightweave.ts Ana
Night weaving…
Completed. Conversations: 2, threads merged: 0, portraits: 2
## Ana
Ana is preparing for a few days of hill walking in the Scottish Highlands with her dog Biscuit, departing the week after 26 October 2026, while taking it easy on a left knee still recovering from a fall. You have advised her on packing and pace … Treat her knee as a continuing constraint, not a passing detail.
## Biscuit
Biscuit is Ana's dog and her companion on a few days of hill walking in the Scottish Highlands …

Next: 21. Sandboxes runs real code for your agents, in a throwaway Linux machine.