Long-lived agent memory is the fastest-growing store of personal data most firms have never classified. It sits in a vector database, it grows on every interaction, and nobody has decided what it is allowed to keep or for how long.
Give an agent memory and it stops being stateless. Every conversation, every retrieved document, every summarised interaction gets embedded and written to a vector store so the agent can recall it later. That is the feature. It is also, from a data-protection standpoint, an ever-growing log of everything the agent has ever seen — customer names, account details, health disclosures, complaints, whatever a user happened to type — held indefinitely, in a store that was chosen for retrieval speed and almost never for retention discipline. Most teams govern this by accident. The store fills up, and one day someone asks where the personal data lives and how it gets deleted, and there is no answer.
Agent memory is personal data, and the embedding is too
The first mental error is treating the vector as something other than the data it encodes. An embedding is a numeric representation of the source text, and the source text routinely contains personal data. Under the GDPR that makes the memory record personal data in scope for the storage-limitation principle in Article 5(1)(e), the data-minimisation principle in Article 5(1)(c), and the right to erasure in Article 17. There is no carve-out for “it’s only a vector”.
Free · 4 minutes
When two of your systems disagree, do you know which one to believe?
Fourteen questions on ownership, lineage, and quality — the difference between a number on a dashboard and a number you could defend. Banded finding on screen, full sheet by email.
The second error is assuming the vector is safe because it is not human-readable. It is not opaque. There is a body of research showing that text embeddings can be inverted to recover a large proportion of the original text — the 2023 work titled “Text Embeddings Reveal (Almost) As Much As Text” being the widely cited example. Treat an embedding of a customer disclosure as you would treat the disclosure itself, because for practical purposes it is a recoverable copy of it. If you would not keep the raw text for two years, you have no basis for keeping its embedding for two years.
Governing agent memory therefore means four concrete controls, applied deliberately rather than inherited from whichever vector database the platform team happened to pick: redact before you embed, put a time limit on every record, delete in a way that actually removes recoverable data, and control what the agent is allowed to recall. None of this is exotic. It is ordinary data lifecycle, applied to a store that usually escaped it because it looked like infrastructure rather than a records system. This is the memory layer that turns a stateless model into a stateful agent — model plus harness, and the harness is where the governance has to live.
Redact on write, not on read
The cheapest control is to keep personal data out of the store in the first place where the agent does not need it to function. Run a named-entity recognition pass over each memory before it is embedded, and replace detected identifiers — names, emails, card numbers, national IDs — with typed placeholders. The agent can still reason over “[PERSON] disputed a charge on [CARD]” for most purposes; it rarely needs the literal card number sitting in long-term memory.
The discipline that matters is doing this before the embedding is computed, not filtering on the way out. Redact on read and you have already stored, and probably backed up, the raw personal data; the vector is already a recoverable copy. NER is imperfect and will miss some entities, so it is a data-minimisation measure, not a guarantee — but a store that has been through a redaction pass on write holds far less recoverable personal data than one that has not, and that difference is exactly what a supervisor or a data-protection officer will ask you to demonstrate.
Time-to-live, and deletion that actually deletes
Every memory record should carry an explicit expiry. Set a default TTL per memory class — short for transient conversational context, longer for durable preferences the agent genuinely needs — and stamp an expires_at on write so a scheduled job can remove anything past its date without a human deciding record by record. A store where retention is a property of each record is one you can reason about; a store that keeps everything until it runs out of disk is not.
Two traps sit here. The first is soft deletion: many vector databases mark a record as deleted and only reclaim it on a later compaction, which means the embedding is still physically present and recoverable in the interim. If your erasure obligation is legal rather than cosmetic, you need to know whether “delete” in your store means gone or means flagged, and you need to trigger the physical removal. The second is orphaned copies — backups, replicas, and any downstream analytics store the memories were streamed into. An erasure request under Article 17 reaches all of them, not just the primary index. Deleting the source text but leaving the embedding, or deleting the live record but leaving the nightly snapshot, is not erasure.
A schema and the jobs that maintain it
The controls above are easier to see in code than in prose. The following uses Postgres with the pgvector extension — where a row-level DELETE genuinely removes the embedding — and Microsoft Presidio for NER-based redaction. The subject identifier on every row is what makes an erasure request a single, auditable query.
# Agent-memory store: per-record TTL, PII redaction on write, scheduled erasure.
# Requires: psycopg[binary], pgvector, presidio-analyzer, presidio-anonymiser.
from datetime import datetime, timedelta, timezone
import psycopg
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine
analyser = AnalyzerEngine() # NER-based PII detection
anonymiser = AnonymizerEngine()
# Default retention per memory class (organisation-set, documented policy).
TTL_BY_CLASS = {
"transient": timedelta(days=7),
"preference": timedelta(days=365),
}
SCHEMA = """
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE IF NOT EXISTS agent_memory (
id bigserial PRIMARY KEY,
subject_id text NOT NULL, -- data subject, for erasure requests
memory_class text NOT NULL,
content text NOT NULL, -- already redacted before insert
embedding vector(1536) NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
expires_at timestamptz NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_mem_expiry ON agent_memory (expires_at);
CREATE INDEX IF NOT EXISTS idx_mem_subject ON agent_memory (subject_id);
"""
def redact(text: str) -> str:
"""Strip detected identifiers before anything is embedded or stored."""
findings = analyser.analyze(text=text, language="en")
return anonymiser.anonymize(text=text, analyzer_results=findings).text
def remember(conn, subject_id: str, memory_class: str, raw: str, embed) -> None:
clean = redact(raw) # redact on WRITE, not on read
ttl = TTL_BY_CLASS[memory_class]
expires = datetime.now(timezone.utc) + ttl
conn.execute(
"INSERT INTO agent_memory "
"(subject_id, memory_class, content, embedding, expires_at) "
"VALUES (%s, %s, %s, %s, %s)",
(subject_id, memory_class, clean, embed(clean), expires),
)
def expire_due(conn) -> int:
"""Scheduled job: hard-delete every record past its TTL."""
cur = conn.execute("DELETE FROM agent_memory WHERE expires_at < now()")
return cur.rowcount
def erase_subject(conn, subject_id: str) -> int:
"""Honour an Article 17 erasure request across the primary store.
Backups and replicas must be reached by their own retention policy."""
cur = conn.execute(
"DELETE FROM agent_memory WHERE subject_id = %s", (subject_id,)
)
return cur.rowcount
Run expire_due on a schedule and TTL enforcement stops being aspirational. Keep erase_subject as a named, logged operation so that honouring a request produces evidence you did it. The comment on the erasure function is the honest part: the primary store is the easy target, and the backups are where the obligation is quietly failed.
Access rules on what the agent may recall
Retention decides what exists; access decides what an agent can pull back into a prompt. A shared memory store that any session can query is a lateral-disclosure risk — the agent recalls one customer’s information while serving another, because nothing scoped the retrieval. Partition memory by subject or tenant and filter every recall on that scope, so the agent can only retrieve what the current interaction is entitled to see. This is the same scoping discipline that applies to any credential or capability: least privilege, enforced at the query, not assumed from the design.
None of this argues against giving agents memory. It argues for treating that memory as what it is — a governed store of personal data with a lifecycle — rather than a convenience that grows without limit. Firms that keep agents on deterministic rails already accept that the interesting risk in an agentic system is rarely the model; it is the state the model accumulates. The board question is not whether the agent remembers. It is whether anyone decided what it is allowed to forget.
Free interactive tool
Interactive deadline calculator
Check which regulations apply to you and when
Regulation across the EU, UK, US and Asia-Pacific has moved considerably in the past eighteen months, and several headline dates have shifted more than once. Twelve questions, about three minutes.
Results are shown on screen — no email required. A dated summary is available to download, and can be sent on if that's more useful. What we do with your answers.
Governance is what happens when nobody is watching.
Policies are easy. Consistent decision-making is harder. Understand where governance exists and where it has quietly become assumed.
Full Governance by Sixteen Pillars
Govern your business. Prove your compliance.
A board assurance cockpit for EU-regulated financial firms — tamper-evident, hash-chained proof of governance across DORA, GDPR, NIS2, ISO 27001, the EU AI Act and MiCA. In development.
See what's coming