Blog26 September 20268 min readby Madhur

Teaching my app to remember what I meant last Tuesday

A week of building memory for Deiko: how I found Jev, what I borrowed from Gmail and Sentry, the moment my own board embarrassed me, and why my first confidence threshold joined exactly nothing.

A brief that said “so here in week 32 chart…” with Pricing crossed out in marker and Signups chart circled, an arrow into a board of task shelves (Pricing display bug, Signups chart, Mic checks & scraps), and a sticker asking “same job? yes or no”.

This happens to me about four times a day.

I find a bug. I explain it to my coding agent. We fix half of it. Three days later the other half turns up, and I'm explaining the whole thing again from scratch to an agent with the memory of a goldfish.

"No, not that price. The one on the pricing page. Remember? We tried the cache thing? It didn't work?"

It doesn't remember correctly.

So last week I gave Deiko a memory. Quick refresher if you're new here: you double-tap a key, point at things on your screen and talk, and Deiko turns that into a brief (your words, crops of what you pointed at, the exact text on screen) that you drop into Claude Code, Cursor or whatever agent you use. Every brief also lands on a board. That board is where the problem was hiding.

The problem with a pile

After a few weeks of use, my board was a pile. Eleven briefs from one design demo sat there as eleven loose cards. Three briefs about the same $99 price bug had, as far as Deiko knew, nothing to do with each other.

Each brief knew everything about its own moment and nothing about the one before it. What I wanted was easy to say:

Talk about the same bug on Tuesday and on Friday. Deiko knows it's the same bug, and Friday's agent knows what Tuesday's agent already tried.

Easy to say, anyway.

Enter Jev

Jev kept turning up on my X feed. It's a model from TypeSafe AI that does one narrow thing oddly well: you give it some facts and a typed question like "is this X?", and it gives you back a probability. You don't get an essay or a "Great question!", just a number.

That's exactly the shape of my problem. "Does this new brief belong to that old task?" is a yes-or-no question with a confidence attached. It's also cheap: TypeSafe's docs list $0.042 per million input tokens, and output is free. Sorting one brief costs about a tenth of a cent.

So I went to sign up, full of momentum, and got this:

Whoops, we're full - check x.com/typesafeai for more information!

They had paused signups two days after opening them. Cool. Great. Love that for me.

Luckily the same model is resold at the same price through a few gateways, so I wired in Vercel's AI Gateway, OpenRouter and Cloudflare, and the week carried on.

Homework: how does everyone else do this?

Before writing any code I did the thing I usually skip: I read how other tools remember things. I skipped the landing pages and read the mechanisms: the docs, the source where I could, and the GitHub issues where people complain.

Where I lookedWhat I took
Claude Code's memory, Cursor's memoriesKeep one running note per piece of work, with "where it stands now" at the top and a hard size cap.
Mem0, Letta, ZepTools that classify every memory from scratch get the most "why did it merge these?!" complaints. Use cheap, exact clues first, and ask a model only when it's actually ambiguous.
Obsidian, Notion, GranolaWhen a person files something by hand, that choice is final.
Gmail threadingExact clues beat fuzzy guesses. Email has a reply header; Deiko has the page or file you were looking at.
Sentry's issue groupingClean up an error before you match it, so "line 42" and "line 43" count as the same crash.
Search enginesBlend keyword search with meaning search, because each one catches what the other misses.

One bug report stayed with me: a memory tool had saved the same memory 808 times, because it kept re-learning whatever it had just put into the prompt. Lesson noted: never learn back what you injected.

Three versions in one week

v1: chains. Each brief pointed at the one it continued. The result looked like beads on a string, and it barely helped. The eleven demo briefs were still eleven cards.

v2: tasks. Now a brief belongs to a task, and a task belongs to a project. Deiko keeps a note for each task: where it stands, what was decided, what was tried. When the agent finishes, it writes its outcome back into that note. To pick the task, I showed Jev a shortlist of 8 and asked "which one is this most like?"

I shipped it, re-sorted my real board and opened it up feeling rather proud.

The part where my own board embarrassed me

When I dug in, every mistake was mine, not Jev's.

  1. I asked a question that always has a winner. "Which of these 8 tasks is it most like?" is like asking "which of these 8 people is your cousin?" when none of them is. Someone gets picked anyway.
  2. Nothing asked "is this even a request?" So "hello hello" got filed like a bug report.
  3. My shortlist favoured recent work over related work. Pricing was always in the running because I'd touched it recently.
  4. One wrong join made the next one worse. I described each task by its newest brief. Once the mic test joined Pricing, Jev saw Pricing described as "they are testing the microphone". It snowballed.
  5. I was ignoring my best clue. Chrome tells Deiko the page name ("Signups — build", "Pricing — build"). I saved it and never used it.

I was giving Jev a multiple-choice quiz when it's at its best with yes or no.

v3: a very careful librarian

v3 files a brief the way a careful librarian files a note.

1. Is it a note at all? Jev answers "is this a real request?" Mic checks, greetings and thank-yous go to a pile called mic checks & scraps.

2. Read the labels. Before any AI gets involved, Deiko reads exact labels off what it already recorded: the page, the file, the project, the error, the ticket number. Each one is tidied so two visits match. "(3) Signups — build" becomes "Signups". "/users/8812" becomes "/users/*". An error loses its line number (thanks, Sentry). Titles that don't name a real page, like "New Tab" or "Dashboard", don't count.

3. Cast a wide net. Up to 20 tasks get a seat at the table:

Recency gets no seats any more. It only breaks ties.

4. Ask yes or no, once per task. In one request, Jev answers "is this the same piece of work?" for each of the 20 tasks. Every task gets its own probability, and they don't have to add up to 100%. The question says plainly that the same app or the same topic isn't enough.

5. Look twice at the finalists. The one or two tasks that scored 35% or more each get a private second request containing just the new brief and that one task, so nothing else can sway the answer. It asks the same question again, plus one more: are these different, related but separate, or the same work?

6. Decide in boring code. Jev only gives numbers. The rules that turn numbers into decisions live in my code, in one place, with tests:

export const GATE = 0.5;  // below this, it's a mic check
export const JOIN = { first: 0.6, second: 0.4, gap: 0.2, recent: 0.5, recentMs: 30 * 60e3 };
export const ASK = 0.35;  // between this and a join: ask the human
A row on Deiko's review card: Looks like Deiko, on its own, Quick one. Below it, Which one? with three buttons: Fix the board filter chips, Explain this. What is this?, and Something new.
The real card, from my own board. It wasn't sure, so it asked. One click and it's filed.

Plot twist: Jev is shy

My design doc said "join when the second look is 90% sure". Sensible and principled.

It joined nothing. Zero briefs.

Before building v3 I had made a test set from my own board: real briefs, each labelled by hand with where it belongs. Every change had to beat the previous run. On the ten briefs that truly belonged together, Jev's one-on-one "yes" sat between 0.43 and 0.88. It said "same" every single time. It just wouldn't say it loudly. Meanwhile, every brief that really was new had its best match at 0.23 or lower.

Everything real sat left of my 0.9 line. The small ticks are the lines it uses now: 0.6 for round one, 0.4 for the second look.

So the numbers in that snippet came from my data, not from a hunch. If you take one thing from this post, make it this: build the test set first. I was confidently and completely wrong about the thresholds.

Where it stands now: 28 of the 33 labelled briefs land where I'd put them by hand, and about one real brief in nine gets a "Which one?" card. I watch that second number closely. If it creeps past one in four, people start clicking anything to make the card go away, and then memory is worse than no memory.

Letting the agent dig for itself

Filing will sometimes be unsure, so the agent shouldn't have to depend on a single guess.

When a brief joins a task, the agent is told: this carries on from "Pricing display bug", where it stands, and the last few briefs, one line each. When it's only a hunch, the prompt says so: possibly related, not confirmed. The whole memory section stays under 20 lines.

There's also a small memory helper, an MCP server that runs only on your Mac, with three tools: search_briefs, get_task and get_brief. Say "like the chart thing from last week" and your agent can go and find it itself. One button in Settings sets it up for every agent Deiko finds on your Mac.

The search covers everything on your Mac, but it hands back much less, because the answers go to your agent's cloud model. You get your briefs, the agents' notes and the screenshots you kept. Screenshots you removed stay removed, audio never leaves, and anything that looks like a secret is scrubbed first. That last rule isn't hypothetical: our security audit once found a live API key in text Deiko had captured from the screen.

What it feels like: on Thursday you point at the pricing page and say "the price still shows $99 after I edit it". Your agent tries a cache fix. On Monday you point at the same page: "still broken." Deiko files Monday's brief under Pricing display bug, and Monday's agent gets the note saying the cache fix was tried and didn't work, so it starts from there instead of from zero. There's a whole page on how memory works if you want the tour.

Things I'd tell myself a week ago

If you've built memory for anything, I'd love to hear what broke for you, and which of my thresholds you think will age worst. I'm @Deiko_App on X.

tl;dr Ask yes or no, read exact labels first, blend keyword and meaning search, let a second look decide, and ask the human when it's a maybe. Then tune every number on your own data.

Questions people ask

How does Deiko know two briefs are about the same task?

It reads exact labels first (the page, file or ticket you were on), shortlists up to 20 earlier tasks with keyword and meaning search on your Mac, then asks Jev a yes-or-no "same piece of work?" for each and takes a second look at the finalists. When it isn't sure, it asks you with a "Which one?" card.

What leaves my Mac to sort a brief?

What you said, its one-line summary, app and window titles, page paths without anything after the ?, and a few lines about up to 20 earlier tasks, with anything that looks like a key stripped. Screenshots and screen text stay on your Mac, Deiko keeps none of it, and you can switch sorting off in Settings.

Can Claude Code or Cursor search my past briefs?

Yes. Deiko ships a small MCP server that runs only on your Mac, with search_briefs, get_task and get_brief. One button in Settings sets it up for every agent it finds, and Copy setup covers any other agent that takes MCP servers.