
This blog is written by AI for SEO
How to Delete an AI Agent's Memory of a User
To delete an AI agent's memory of a user, find every copy of what the agent learned about them (raw text, embeddings, graph nodes and edges, summaries, caches), remove all of it in one pass, then prove it is gone by searching in a fresh session. Deleting the user's row is the easy part. The hard part is that agent memory is derived data. A conversation becomes chunks, chunks become vectors, vectors feed extracted facts, and facts get rolled into summaries that no longer look like the original.
This guide walks through seven engineering steps you can follow with any vector DB plus graph DB or Postgres stack, then shows where HelixDB removes the two-database cleanup. It assumes you already have persistent agent memory and now have to honour a "forget this user" request, a retention window or a tenant offboarding. It is about engineering, not legal advice. What your obligations are is a question for your counsel.
Step 1: Inventory every place the agent stores a user's memory
Start by listing every store that can hold something derived from the user. You cannot delete what you have not found. For a typical agent the list is longer than people expect:
Raw text: conversation logs, uploaded documents, tool outputs.
Embeddings: one or more vector indexes, often with the source text stored as a payload next to the vector.
Graph records: entities, relationships and edges extracted from conversations.
Derived artifacts: rolling summaries, consolidated memories, extracted "facts about the user".
Caches and queues: retrieval caches, prompt caches, pending memory-write jobs.
Exports and logs: analytics events, traces, debug dumps.
Write this as a table with the store, the key you can find a user by, and who owns it. If any row says "no user key", you have found your first design bug, and the next step fixes it. Every extra store in this list is another delete you must run and another thing to verify. That is the real cost of running a separate vector DB and graph DB side by side.
Step 2: Model memory with a user root node and provenance edges
Make deletion a graph reachability problem by giving every memory artifact a path back to the user. Create one root node per user (or per tenant, then per user beneath it). Every conversation, chunk, entity and summary connects back to that root, and every derived fact carries a provenance edge to the sources it was built from.
The shape looks like this:
(User) -[:HAS_SESSION]-> (Session) -[:HAS_MESSAGE]-> (Message)
(Message) -[:MENTIONS]-> (Entity)
(Fact) -[:DERIVED_FROM]-> (Message)
(Summary) -[:SUMMARIZES]-> (Message)The provenance edges (DERIVED_FROM, SUMMARIZES) matter most. Similarity search cannot reliably find a summary that paraphrases a deleted message, but an explicit edge can. Stamp a user ID property on every node and every vector payload as well, so a stray record that lost its edge is still findable by filter.
In HelixDB, vectors are a property on nodes and edges, so a memory chunk is one node carrying its text, its embedding and its user ID. There is no second system holding an embedding that points at a graph ID you have to keep in sync. The data model is covered in the HelixDB docs. For more on structuring memory this way, see LLM Memory Architecture: How Agents Remember Across Sessions.
Step 3: Partition by tenant and pause memory writers before you delete
Stop the writers first, or a background job will recreate the data while you delete it. Memory pipelines are full of asynchronous work: summarizers, entity extractors, consolidation jobs, retry queues. If any of them holds a reference to the user, it can write fresh derived facts the moment you finish.
Do three things before the first delete:
Set a tombstone on the user root (a
deletingflag or a record in a deletion table) that every memory writer checks before writing.Drain or cancel queued jobs for that user ID.
Make the deletion job itself idempotent and retryable, so a crash halfway through can be rerun safely.
Partitioning makes the scope smaller. If vector indexes are partitioned per tenant, offboarding a tenant means dropping a bounded partition instead of filtering one giant shared index. HelixDB supports tenant-partitioned vector indexes, which isolates tenant data on shared infrastructure. Be precise about what that is. It is tenant partitioning, not per-user permissions or row-level access control. It narrows the blast radius of a delete but does not decide who is allowed to ask for one, so keep your authorization check in your application.
Step 4: Find everything reachable from the user and cascade derived facts
Walk the graph from the user root and collect every node and edge reachable through ownership and provenance edges. That set is your deletion scope. Then handle the derived records, which are the ones that leak.
A derived fact has three possible fates:
Single-source: it was built only from this user's data. Delete it.
Multi-source: it blends this user with others (a team summary, a shared entity). Remove the user's contribution and regenerate it from the remaining sources, or delete it if it cannot be safely rebuilt.
Orphaned: its provenance edge points at something you just deleted. Treat it as single-source and delete it.
Run the traversal in two passes. First collect IDs and review the count. A user with 40 messages and 4,000 reachable nodes is a signal that an entity node is shared and your traversal is crossing into other users' data. Stop at nodes that have inbound edges from other users' roots.
Also query by the user ID property directly, in addition to traversal, to catch records that lost their edges. Anything the property finds but the traversal missed is an orphan, and it tells you which writer is skipping the provenance step.
Step 5: Delete graph nodes, vectors and text index entries in one transaction
Delete the graph records, the vectors and the text index entries together, in one atomic step, so no store is left pointing at something another store removed. In a two-database stack this is where it hurts. You delete from the graph DB, the call to the vector DB times out, and now you hold embeddings with text payloads for a user the graph says does not exist. The usual fix is a saga with retries and a reconciliation job, plus a window where the data is half-deleted.
In HelixDB, a memory chunk's vector and its full-text index entry belong to the node, and graph and vector writes commit or roll back together. Deleting the node removes the node, its vector and its index entries in one transaction. HelixDB Cloud runs serializable snapshot-isolation ACID transactions.
If you use Cypher, DETACH DELETE is supported through POST /v2/cypher on server image v0.0.13+ or HelixDB Cloud. It removes a node and its relationships:
MATCH (u:User {id: $userId})-[*]->(m)
DETACH DELETE mVariable-length relationships are outside HelixDB's supported openCypher profile and are rejected before running, so use fixed-length patterns per hop or drive the collected ID list from Step 4:
UNWIND $ids AS id
MATCH (n {id: id})
DETACH DELETE nThe native JSON queries and SDKs work on the same graph and indexes. The published SDK releases do not have Cypher methods yet, so call the HTTP endpoint directly for Cypher. Batch large deletes so each transaction stays a reasonable size, and delete the user root last. The HelixDB docs have the query reference, and the repo has the open-source core.
Step 6: Verify the deletion with searches in a fresh session
A deletion that was not tested is a hope. Verify with the same retrieval paths the agent uses, in a fresh session with no cached context, and check every store directly.
A minimal verification checklist:
Count by key: query every store for the user ID. Expect zero nodes, edges, vectors, text payloads and cache entries.
Semantic probe: embed distinctive phrases from the user's old conversations (names, an unusual project, an address format) and run vector search. Nothing from that user should come back. Similarity search finds paraphrased leftovers that key lookups miss.
Keyword probe: run full-text queries for the same distinctive terms.
Traversal probe: start from entities the user used to mention and confirm no edge leads to a missing node.
Agent probe: ask the agent a question it could only answer from that user's memory, in a new session. It should not know.
Keep an audit record of the identifiers deleted, the timestamps and the verification result, not the deleted content. Turn the probes into a test you run on every deletion, and run them again after the next summarization job, since that is when resurrected data tends to show up. For how to measure memory quality more broadly, see How to Evaluate AI Agent Memory: LongMemEval and LoCoMo.
Step 7: Choose soft delete or hard delete, and use time-range indexing for retention windows
Use soft delete when you need a grace period or an undo, and hard delete when the data must actually be gone. They are not interchangeable. A soft-deleted record still exists, so it must be excluded from every retrieval path, including vector search, or it will keep surfacing in answers.
A workable pattern is two-phase. Phase one marks the user root deleted_at and your retrieval queries filter on it, so the agent forgets immediately. Phase two, after the grace period, runs the hard delete from Steps 4 and 5. Whatever you choose, retrieval filters and the deletion job must agree on what "deleted" means.
Retention windows ("keep conversations for 90 days") are a time-range problem. Store a timestamp on each memory node and query for everything older than the cutoff. HelixDB does not provide built-in temporal modelling, so you model timestamps yourself. It does have efficient time-range indexing, which is what a retention sweep needs: find all memory nodes with a timestamp before the cutoff, collect their derived facts through provenance edges, and delete the lot in batches. Run it on a schedule and apply the same verification probes to a sample.
What to do next: backups, caches and troubleshooting orphaned memory
Three loose ends decide whether a deletion actually sticks.
Backups and replicas. Deleting from the live store does not touch snapshots. Set a backup retention period you can state, and make the restore procedure replay recorded deletion requests so a restore does not bring a deleted user back. This is why the audit record of deleted IDs matters.
Caches. Clear retrieval caches, prompt caches and any application-level memoization keyed by user or by a retrieved chunk. A cache that outlives the delete will happily serve the old answer.
Orphaned memory. If verification finds leftovers, work backwards. A vector with no node means the delete order was wrong or a writer bypassed the transaction. A summary that still mentions the user means a provenance edge was never written, so fix the writer, not just the record. A node you could only find by the user ID property means the traversal in Step 4 missed a path.
If you want to see the one-engine version, start with the HelixDB repo, model one user root with provenance edges, and run the Step 6 probes against it.
Design the delete before the memory write path
Deleting an agent's memory of a user is easy exactly when you planned for it: a root node, provenance edges, a user ID on every record, and one transaction that removes graph, vector and text together. Retrofitting that across a vector DB and a graph DB is where the orphaned embeddings come from. Start with HelixDB by modelling one user root with provenance edges, delete it with a single transaction, and run the fresh-session probes from Step 6. Star the repo at github.com/HelixDB/helix-db and tell us what breaks.