DEV Community

Cover image for AI memory should be a product state, not a prompt trick
Yana Li
Yana Li

Posted on

AI memory should be a product state, not a prompt trick

User agency and tiered memory architecture

I ran into a memory problem while building a reflective AI product.

The easy version of AI memory is tempting:

Save useful facts about the user.
Put them back into the next prompt.
Call it memory.
Enter fullscreen mode Exit fullscreen mode

That can work for low-risk personalization.

It is probably fine if an assistant remembers that a repo uses pnpm, or that a user prefers short answers, or that a team calls its staging branch preview.

But the problem changes when the user is bringing personal material into the product.

In my case, the product lets people explore dreams, moods, relationship patterns, recurring symbols, and private reflections. I did not want meaningful sessions to disappear into raw chat history. But I also did not want every sentence the user typed to quietly become permanent memory.

That changed the architecture for me.

The question stopped being:

What can the model remember?
Enter fullscreen mode Exit fullscreen mode

It became:

What does the user own?
What did they approve?
When is it stored?
When is it used?
When can it be paused, exported, or deleted?
Enter fullscreen mode Exit fullscreen mode

That distinction sounds like product design, but it quickly becomes system design.

The common mistake: treating memory as one bucket

Many AI products describe memory as if it were one thing:

Memory: on/off
Enter fullscreen mode Exit fullscreen mode

That is simple, but it hides too much.

In practice, "memory" usually mixes several different jobs:

  • short-term conversation context
  • a summary of the last session
  • facts the user explicitly wants remembered
  • model-inferred patterns
  • user-authored background context
  • retrieval results selected for the current turn
  • account data that must be exportable or deletable

If all of that becomes one invisible bucket, the developer gets a simpler implementation and the user gets a murkier product.

You also lose the ability to answer basic questions:

  • Why did the assistant bring this up?
  • Did it save that automatically?
  • Is this being used in future prompts?
  • Can I delete this one thing without deleting everything?
  • What happens if I pause memory?
  • What happens if my subscription ends?

Those are not only UX questions. They are architecture questions.

Stored memory and prompt memory are different

The biggest architectural shift for me was separating stored memory from prompt-time memory.

A user may own saved memory assets, but that does not mean the model should always be allowed to use them.

I ended up thinking about memory in two different states:

This belongs to the user.
This is currently allowed to enter the prompt.
Enter fullscreen mode Exit fullscreen mode

Those are not the same promise.

A user should be able to view, export, or delete saved memory without the assistant automatically using it in every future session.

That separation led to a small but important access layer:

type MemoryAccessState = {
  userMemoryEnabled: boolean;
  planKey: string;
  entitlementState: string;
  subscriptionActive: boolean;
  canUsePromptMemory: boolean;
  pendingMemoryActivation: boolean;
  memoryExpiresAt: string | null;
};

function getCanUsePromptMemory(state: MemoryAccessState) {
  return state.userMemoryEnabled && state.subscriptionActive;
}
Enter fullscreen mode Exit fullscreen mode

The important field is not userMemoryEnabled.

It is canUsePromptMemory.

That field answers the real runtime question: should memory be included in the prompt for this turn?

This avoids a confusing product promise.

For example:

  • a free user may have memory assets saved, but not active in future prompts
  • a paid user may allow long-term memory into sessions
  • a user may pause memory without deleting the assets
  • an interrupted subscription may retain memory for a defined period without letting the model call it
  • deletion and export can still work even when prompt memory is disabled

Without this separation, memory becomes a hidden privilege state. The data exists, the user sees some of it, the model may or may not use it, and nobody can explain the boundary clearly.

The pattern: split memory by lifecycle

I stopped treating memory as one feature and started treating it as a set of product states.

The simplified shape looks like this:

conversation
-> session note
-> user-approved memory item
-> user-authored room context
-> long-term inner map
-> retrieval evidence
-> prompt context
Enter fullscreen mode Exit fullscreen mode

Each layer has a different lifecycle.

conversation is the raw exchange. It is useful for same-session continuity, but too noisy to become long-term memory by itself.

session note is a structured artifact created after a session. It can summarize themes, symbols, conflicts, and useful continuity points.

memory item is smaller and more explicit. It is the kind of thing the user can inspect and approve.

room context is user-authored background. I treat this as higher-trust than inferred memory because the user wrote it directly.

inner map is a versioned long-term snapshot of recurring themes. This layer needs caution because it can easily sound more authoritative than it is.

retrieval evidence is what the system selected for the current turn.

prompt context is the final compiled memory that the model sees.

This adds work, but it makes the system easier to reason about.

The user can own assets without every asset being active in the prompt. The assistant can use relevant memory without pretending all saved history is equally important. The product can pause, retain, export, or delete different layers without inventing a new exception every time.

Retrieval should return evidence, not vibes

Once memory is layered, retrieval should also become more explicit.

A memory result should not just be text pasted into a prompt. It should carry enough metadata to explain why it was selected.

A simplified version:

type MemoryEvidence = {
  source: "session-note" | "memory-item";
  id: string;
  title: string;
  excerpt: string;
  score: number;
  reason: string;
  createdAt?: string;
};
Enter fullscreen mode Exit fullscreen mode

The reason field is not fancy, but it is useful.

It can say things like:

semantic long-memory match
strong theme/symbol overlap
partial approved-memory overlap
recent continuity evidence
Enter fullscreen mode Exit fullscreen mode

This helps debugging, but it also keeps the product honest.

If the assistant brings a memory into the current turn, the system should be able to explain why that memory was selected.

For a first version, retrieval does not need to be magical. I prefer a conservative hybrid approach:

user-authored context
+ latest long-term snapshot
+ relevant session notes
+ recent notes as fallback
+ approved memory items
-> compact prompt memory
Enter fullscreen mode Exit fullscreen mode

Vector search is useful, but it should not be the only rule.

For personal or reflective products, recency, explicit approval, user-authored context, and clear fallback behavior matter just as much as similarity score.

A small failure case: the creepy callback

Here is the kind of behavior I wanted to avoid.

Suppose a user once wrote:

I keep dreaming about a locked garden gate.
Enter fullscreen mode Exit fullscreen mode

Two weeks later they write:

I felt ashamed today when I wanted to ask for help.
Enter fullscreen mode Exit fullscreen mode

Bad memory behavior:

This connects to your locked garden gate dream.
Enter fullscreen mode Exit fullscreen mode

Maybe it does. Maybe it does not.

The callback may be clever, but if the user did not invite that connection, and the system cannot explain why it surfaced the memory, it can feel creepy.

Better behavior:

There may be a threshold theme here, but I would not force it.
If it feels connected, we can compare today's shame with the earlier gate image.
If not, we can stay with what happened today.
Enter fullscreen mode Exit fullscreen mode

The wording is different, but the real difference is architectural.

The system needs to know:

  • Was the earlier note user-approved or model-inferred?
  • Was it selected because of semantic similarity, theme overlap, or mere recency?
  • Can the user inspect it?
  • Can the user delete it?
  • Can memory be paused before the next turn?

If those answers only exist inside the model response, the product is too soft in the wrong place.

The memory boundary needs to exist outside the prompt.

Retention is also part of memory design

Another mistake is treating retention as a legal/privacy page problem only.

For memory-heavy products, retention is part of the product behavior.

I prefer making the rules boring and explicit:

Active subscription:
  memory can accumulate
  memory can enter prompts if enabled

Paused or interrupted subscription:
  memory assets are retained for a defined period
  memory does not enter prompts

Memory disabled:
  existing assets remain manageable
  new long-term memory writes stop

Deletion:
  individual memory items can be deleted
  account-owned data can be exported or removed
Enter fullscreen mode Exit fullscreen mode

The important part is not the exact number of days. The important part is that the product does not blur ownership, access, and usage.

A user should not have to guess whether saved memory is currently active.

They should not have to delete everything just to stop the assistant from using it.

Guardrails I would keep

For sensitive or reflective AI products, I would start with these guardrails:

  1. Do not treat the raw transcript as the long-term memory layer.
  2. Create a structured session note before creating smaller memory items.
  3. Require explicit approval for strong long-term memory items.
  4. Separate stored memory from prompt-time memory.
  5. Show memory state in account or session UI.
  6. Let users pause memory without deleting saved assets.
  7. Let users delete individual memory items.
  8. Keep export and deletion paths boring and reliable.
  9. Record why retrieved memory entered the prompt.
  10. Make retention rules explicit when billing or account state changes.

None of this requires a complicated agent framework.

It requires treating memory as product state instead of prompt decoration.

Where this is probably overkill

This pattern is too heavy for some products.

I would not build all of this for:

  • a throwaway demo
  • a stateless assistant
  • a tool that only remembers harmless UI preferences
  • a private local prototype where the user and developer are the same person

It becomes worth it when:

  • users bring sensitive or personal material
  • memory changes future model behavior
  • the product has accounts, billing, export, or deletion promises
  • users may reasonably ask why the AI remembered something
  • continuity is part of the paid value

That last point matters.

If memory is part of what people pay for, it cannot just be a prompt trick.

How I am applying this

I built this pattern while working on Jung Room, a non-clinical AI self-exploration room for dreams, moods, symbols, and recurring patterns.

The product-specific version has:

session notes
+ saved memory items
+ user-authored room context
+ inner-map snapshots
+ account memory controls
+ subscription-gated prompt-time memory
+ retention and deletion paths
Enter fullscreen mode Exit fullscreen mode

The general lesson is broader than this product:

Memory should be inspectable before it becomes powerful.
Enter fullscreen mode Exit fullscreen mode

Builder checklist

If you are adding memory to an AI product, these are the questions I would ask early:

  • What exactly is being stored?
  • Which parts were written by the user?
  • Which parts were inferred by the model?
  • Which parts require explicit approval?
  • Which parts can enter future prompts?
  • Can the user pause prompt-time memory?
  • Can the user delete one memory without deleting the account?
  • What happens when billing state changes?
  • What is the fallback when retrieval fails?
  • Can you explain why a memory was selected?

If those answers are unclear, the memory feature may work technically while still feeling untrustworthy.

Open question

How are you handling memory in your own AI apps?

Are you treating it as private prompt context, user-owned product state, retrieval evidence, or something else entirely?

Top comments (13)

Collapse
 
jugeni profile image
Mike Czerwinski

Strong framing — "inspectable before powerful" is the line that should be on every memory-system whiteboard.

I've been building this exact pattern for ~6 months in my own ops assistant (decisions / threads / notes as separate stores, each with its own lifecycle). A few things that emerged in practice that your post doesn't fully cover:

Decision lifecycle matters more than memory lifecycle. I have proposed → accepted → locked states for decisions specifically — "locked" means the model is forbidden from re-litigating it without explicit unlock. Pure memory-access toggles don't capture that a fact can be defended vs recallable.
Source-anchoring beats consent toggles. Every note atom carries its source (which email, which call, which file:line). When retrieval happens, the model sees provenance, not just content. Solves a different problem than canUsePromptMemory but kills the same class of hallucination.
The hardest part isn't architecture — it's the capture habit. A clean schema with no discipline to write to it post-session is worse than no schema. Curious how you're solving the "who writes the structured note, model or user" question.
Would love to read a follow-up on retrieval reasoning specifically — that section was the thinnest and it's where most production systems quietly cheat.

Collapse
 
woshiliyana profile image
Yana Li

I really like the way you separate decision lifecycle from memory lifecycle. I didn’t cover that enough in the post.

The distinction makes sense to me: a memory can be recallable material, but a decision is closer to a boundary or commitment the user has already made. If something is truly locked, the model should not keep re-litigating it unless the user explicitly unlocks it.

I’d be a little careful with “locked” in reflective AI, though. A person’s understanding of themselves can change, so I would not want every inner theme to become a fixed decision. But explicit boundaries, preferences, no-go areas, account choices, and user-approved operating rules probably do deserve a stronger decision state than ordinary memory.

On source anchoring, I agree. I see it less as a replacement for consent and more as the other half of it. Consent answers: “is this allowed to be used?” Provenance answers: “where did this come from, why should we trust it, and why is it showing up now?” Without provenance, memory can easily turn into confident-sounding model voice with no visible ground.

For structured notes, my current bias is: model drafts, user approves. The model can write the session note and suggest memory candidates, but I don’t want it silently upgrading sensitive material into durable memory. The user should be able to see it, edit it, save it, or ignore it.

And yes, I think you’re right that retrieval reasoning is the thin part. The storage schema is only the first half. The harder part is prompt-time selection: why this memory, why not another one, and when should the system choose not to bring anything up at all. That probably deserves its own follow-up post.

Collapse
 
jugeni profile image
Mike Czerwinski

The caution about over-locking in reflective AI lands. Boundaries, no-go areas, account choices want a status field. Self-understanding doesn't — locking it freezes what the user is still working out. That belongs in memory lifecycle with provenance, not the decision store.

Consent and provenance as two halves is the framing I'll be stealing. One asks if the memory is allowed to be used. The other asks if it earned its place at all. Without provenance, durable memory ends up sounding confident with nothing under it.

Retrieval reasoning being the thin part is exactly where I keep landing in practice. Not in theory — in the daily mechanic of "you can't carry the whole session forward, so what do you press the juice out of." After enough sessions you stop thinking in storage and start thinking in distillation: which moments shaped the flow of thinking, which ones were noise, which ones the next session needs to open with so it walks in already standing somewhere. That's a different system from storage and locks — it's about what gets carried. You're right it wants its own post. If you write it I'll read it; if I write it first I'll send it.

Thread Thread
 
woshiliyana profile image
Yana Li

Really happy we got to explore this so deeply.

I really like your framing of “what gets carried.” Storage answers what exists. Locks answer what should not be casually reopened. But carry-forward asks a more product-shaped question: what should the next session inherit?

For reflective AI, I don’t think this should be only a similarity or summary problem. The thing worth carrying may be the moment that changed the user’s framing, a boundary they clearly set, or an unresolved tension they chose to keep open. And sometimes the right answer is to carry nothing forward, because forced continuity can make the system sound more confident than it should.

That is why I’m starting to think of session notes less as summaries and more as handoff artifacts. They should give the next session continuity, but not let the system pretend it fully understands the user.

I’d love to keep writing in this direction. Thanks for pushing the question one step further.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Thanks, this is the cut I was groping toward and you sharpened it. The shift from "summary" to "handoff artifact" does most of the work, because it names the reader. A summary has no addressee, it tries to compress everything for nobody in particular. A handoff artifact has a next session that will pick it up, and that constraint changes what is worth writing down.

Your three classes (framing-change moments, boundaries set, unresolved tensions kept open) cover most of what I want carried in my own work. The one I would add as a fourth, and I think it sits next to your boundary class, is the moment the user corrected the system. Corrections encode both what the system got wrong and the repair the user supplied, and they are the only carry-forward where the next session can verify against the previous one without re-deriving the conclusion. A framing-change moment is hard to falsify in the next session. A correction is testable on the next similar input.

The "nothing carried" case is the one I think is most underwritten. Forced continuity does make the system sound more confident than it should, and it also makes the user responsible for refuting an inheritance they did not ask for. Carrying nothing forward shifts the burden the right way. The next session has to earn the context, the user does not have to dismantle it. That asymmetry feels right.

The piece I have not figured out yet, in case you want a thread for the next post: who authors the handoff artifact. If the model writes it, it can quietly carry forward the version of the user it found most legible. If the user writes it, the cost is high enough that most users will not. The middle case I keep landing on is the model drafts and the user ratifies, which is structurally what we are doing in this thread, but I do not know if that scales below the threshold of a willing reader.

Thread Thread
 
woshiliyana profile image
Yana Li

The correction point feels especially right to me.

I had been thinking about carry-forward in three buckets: moments that change the framing, boundaries the user sets, and unresolved tensions they choose to keep open. But you’re right that corrections deserve their own class. A correction is not just a preference signal. It is a repair event: the system got something wrong, and the user supplied the fix. The next session should be able to prove it learned from that by not making the same mistake on similar input.

I also agree that the “nothing carried” case needs more attention. A lot of memory products seem to assume continuity is always good. But unasked-for continuity can put the burden on the user. They have to undo an inherited context before they can move on with the current one. Sometimes carrying nothing forward is the more respectful choice, because the next session has to earn the context again instead of pretending it already has it.

On who authors the handoff artifact, I think that may be the real question for the next post. If the model writes it alone, it may preserve the version of the user it finds easiest to understand. If the user has to write it, the cost is too high. So the middle ground does seem to be: the model drafts, the user ratifies.

The hard product problem is making that ratification light enough. It cannot feel like reviewing a document every time. It probably has to be closer to approve, delete, edit one line, or mark “don’t carry this.” Otherwise it only works for people like us who are willing to read this deeply.

So yes, I think the next piece is probably about that: AI memory is not only about what gets stored. It is about who gets to decide what is carried forward.

Thread Thread
 
jugeni profile image
Mike Czerwinski

The "model drafts, user ratifies" middle ground is the load-bearing shape, but it has the same authorship bite one level up. The model picks what to surface for ratification, so the user's ratification window is whatever the model already surfaced. What never gets drafted never gets a chance to be carried, and the user can't review what they don't know exists. The ratification UX inherits the model's blind spots, just laundered.

The breakout, if you want it: include a small randomly-sampled control set in the ratification surface. "Here are 5 things I think you'd want carried forward, plus 2 random snippets from this session that I didn't flag. Quick check on each." The user's reaction to the random pair is the signal that tells you whether the surfacing layer is calibrated. Without it, you're auto-tuning on prior user picks, which trains you toward whatever they were already comfortable seeing.

"Who gets to decide what is carried forward" as the next-post framing is the cut. The honest version is probably: the user decides, but the system has to make sure the user's deciding set isn't quietly authored by the system.

Collapse
 
icophy profile image
Cophy Origin

This distinction between "stored memory" and "prompt-time memory" is something I've had to work out the hard way too. I run a persistent AI agent (Cophy) where memory is split into roughly three tiers: a hot Core layer (MEMORY.md, ~6000 tokens, loaded every session), a warm daily log layer (episodic, date-stamped), and a cold semantic search layer for deep retrieval. Your canUsePromptMemory concept maps exactly to the question I ask at the Core layer boundary — not "does this exist?" but "should this be active right now?"

The creepy callback failure mode you describe is real and subtle. My solution was to make retrieval evidence-bearing before it enters reasoning: each recalled snippet carries its source path and line number, so I can explain why something surfaced rather than just that it did. It doesn't fully solve the problem, but it makes the boundary auditable.

One thing I'd add to your builder checklist: when does a memory expire? Raw recency and semantic similarity both miss the "this fact is stale" problem. I run a nightly Dream Cycle that ages out low-value episodic entries before they can drift into the Core layer — treating memory consolidation as a first-class scheduled job rather than an incidental side effect.

Your final point lands hard: if memory is part of what people pay for, it can't be a prompt trick. The architecture has to be honest enough that you could show it to a user.

Collapse
 
woshiliyana profile image
Yana Li

I agree with almost all of this, especially the expiry point.

My post focused more on the boundary between stored memory and prompt-time memory, but staleness is the next hard problem. A memory system cannot just keep accumulating material because it was once relevant.

Some memories should stay core, some should remain episodic, some should be retrieved only with evidence, and some should quietly age out or ask for re-confirmation.

I also like your phrase “evidence-bearing retrieval.” That is the direction I care about too: if something enters the prompt, the system should know where it came from and why it is showing up now. Otherwise memory becomes a confident voice with no visible ground.

And yes, if memory is something people pay for, the architecture has to be honest enough to show to the user.

Collapse
 
voltagegpu profile image
VoltageGPU

As an engineer working with GPU infrastructure, I've seen how offloading memory management to the hardware layer (like with VoltageGPU's secure enclaves) can help maintain state more reliably than prompt-based tricks. For reflective AI systems, having a consistent and secure memory context is crucial—otherwise, you're just papering over the gaps in the model's understanding.

Collapse
 
woshiliyana profile image
Yana Li

I agree that secure infrastructure helps a lot, especially for confidentiality and execution boundaries.

But I’d separate that from the product question: even if memory is stored or processed securely, the product still needs to decide what was user-approved, what can enter the next prompt, and what can be paused, exported, or deleted.

For reflective AI, “secure by default” should not accidentally become “remembered by default.”

Collapse
 
nazar-boyko profile image
Nazar Boyko

Splitting userMemoryEnabled from canUsePromptMemory is the part that earns the whole post. Most "memory on/off" toggles quietly conflate "I own this data" with "the model may use it right now", and that's exactly where the trust leaks. The creepy callback example lands for the same reason. Even your softer wording still reveals the system kept that gate dream around, which a paused user might not expect. How do you decide which approved items actually make it into a turn once you're past a token budget? If it's a similarity score, recency and explicit approval can lose to something that's just textually close, which feels like the wrong default for sensitive material.

Collapse
 
woshiliyana profile image
Yana Li

I agree with this concern. For sensitive material, I would not want a similarity score to be the only selector.

The way I’m thinking about it now is in two steps.
First: is this memory even eligible to be used in this turn?
Second: if it is eligible, is it actually useful enough to bring into the prompt?
In the product I’m building, I separate stored memory from prompt-time memory first. A saved memory can exist as something the user owns, without automatically becoming something the model can use right now. It only becomes a candidate when memory is enabled, the account state allows prompt memory, and the item has not been paused or deleted.

But I think you’re right that this still isn’t enough for sensitive material. Similarity should be a way to find candidates, not final permission. I would want the system to also care about current user intent, freshness, sensitivity, whether the user has invited that theme back into the room, and whether we can explain why that memory surfaced.

I’m starting to think that, for reflective AI, “not retrieved” is often a better failure mode than “surprisingly remembered.”