zepto-claw · Episode 6

I gave my AI agent a long-term memory

It remembers the important stuff — weeks later, even after the chat scrolls away.

Building your own claw — a series where we build a tiny AI agent one small piece at a time.

▶ Watch the build on YouTube

Last episode I said personality was next. But here's the thing — a personality that doesn't remember you is just a costume. Before the claw can act like it knows you, it has to actually know you. So first, a memory that lasts. Then the personality.

Watch what that buys you. Today I tell the claw, in passing, "btw I'm allergic to peanuts." It quietly writes it down. Three weeks later, in a brand-new chat, I ask "find me a dinner spot" — and it suggests one, then adds "I'll skip the peanut dishes." I never mentioned the allergy again. It just remembered.

The problem

Back in E02 I gave the claw a memory: every message, written to SQLite, replayed into the prompt so it remembers what was said. That's the right first step — but it has a ceiling. A raw transcript grows forever, and eventually it has to be trimmed to fit the context window. When that happens, the oldest turns fall off the end — and the oldest turns are often exactly where the important facts live. "I'm allergic to peanuts," mentioned once, three weeks ago, is the first thing to get scrolled away.

The fix isn't a bigger transcript. The important facts shouldn't decay just because the chat got long. They deserve their own place — a short, curated list that rides above the conversation and never gets trimmed. A diary.

The code

The diary is built from two pieces you've already seen: a tool (E04) and a SQLite table (E02). First, a remember tool the claw calls on its own when it learns something worth keeping.

// claude.ts — a tool the claw calls when it learns something worth keeping.
tool("remember",
  "Save a durable fact about the user — name, preferences, goals. " +
  "Use sparingly: only things worth recalling days later, never small talk.",
  { note: z.string() },
  async ({ note }) => {
    addNote(note);
    return text(`noted in diary: ${note}`);
  });

That's the writing half. The reading half lives in ask(): before every chat, we pull the whole diary out of the table and paste it on top of the prompt.

// claude.ts — every chat starts by reading the diary back in, up top.
const notes = getNotes();
const diary = notes.length
  ? `(Your diary — durable facts about the user:\n- ${notes.join("\n- ")})\n\n`
  : "";
const fullPrompt = diary + (history ? `${history}\nuser: ${prompt}` : `user: ${prompt}`);

The table itself is three lines in db.ts: a diary table and a pair of helpers, addNote and getNotes. Same shape as the messages table from E02 — just a different list, one the claw curates instead of one that records everything.

How it works

The trick is two parts working together. First, the claw decides what to keep. remember is just another tool, and the prompt tells the model when to reach for it: durable facts only — a name, an allergy, a goal — never chatter. So the diary stays short and meaningful, a handful of things that matter rather than a dump of every word.

Second, every conversation is seeded with the whole diary up top, above the rolling transcript. The history can grow and get trimmed all it likes; the facts ride above it, in their own block, so recall doesn't decay as the chat gets long. That's the difference from E02 in one line: E02 was the raw transcript — what was said, fading from the back. E06 is a curated diary of durable facts — what matters, that persists.

So when I say "I'm allergic to peanuts," the model calls remember and a row lands in the diary table. Weeks later, in a fresh chat with no shared history, ask() still pastes that diary at the top — and the model reads "allergic to peanuts" before it ever picks a restaurant. The recall is unprompted because the fact was there the whole time.

One caveat — the claw decides what to keep

The agent curates the diary itself, which is the magic and the catch. It can mis-remember, save the wrong thing, or hold onto a fact that's gone stale. A real diary wants two more pieces: an edit/forget command so you can correct or remove a note, and a size cap so it can't grow without bound and swamp the prompt. Small first, though — recall before polish. One tool and one table teach the whole idea.

Try it yourself

  1. Add a diary table with addNote / getNotes to db.ts, the remember tool to claude.ts, and prepend the diary in ask() before the history.
  2. Run it: npm run whatsapp, then tell it a durable fact — btw I'm allergic to peanuts. Watch it call remember.
  3. Start a brand-new chat and ask something related — find me a dinner spot — and watch it recall the allergy on its own. Ask what do you know about me? to read the diary back.

Watch the full build: the zepto-claw E06 Short, and subscribe on YouTube for E07. Catching up? Start with E01 · E02 · E03 · E04 · E05.