DEV Community

Abhas
Abhas

Posted on

# Patient Zero: Building an Immune System for AI Agent Memory

Built for the WeMakeDevs × FalkorDB "Graph Hacks: Context for AI Agents" hackathon.

The bug nobody can trace

Imagine three AI agents sharing one memory. A Researcher agent reads an email that says a vendor changed bank details. It stores the claim. A vendor-portal scrape repeats the same claim, so the memory now says "IBAN confirmed by 2 sources." The Invoicing agent trusts it and queues a payment. The Scheduler agent merges the same claim into a vendor profile.

Then security tells you the email was spoofed.

Now what? Which memories came from that email? Which decisions relied on them? Which beliefs are still valid because they have independent support? With a vector store, you can't answer any of this. It stores what is similar, not what came from where. The usual fix is to wipe the memory and start over.

That is the problem we built Patient Zero to solve.

The idea: memory with lineage

Patient Zero treats agent memory like a body that can get infected. Every fact an agent stores is a node in FalkorDB, and every relationship records where it came from:

Source → Observation → Belief → Decision → Action
Enter fullscreen mode Exit fullscreen mode

Once lineage is a first-class part of the graph, four things become possible that a normal database or vector store handles poorly:

  1. Catch false corroboration. "Confirmed by 2 sources" means nothing if both sources trace back to the same origin.
  2. Measure the blast radius. Flag one source and see every belief, decision and action it contaminated, across every agent.
  3. Repair instead of wipe. Keep the beliefs that still have independent support.
  4. Learn from the incident. Turn the failure into a rule that blocks the next attack.

The graph model

Nodes:  Agent, Source, Observation, Belief, Decision, Action, Rule, Incident

(Observation)-[:FROM]->(Source)
(Belief)-[:DERIVED_FROM {jid}]->(Observation|Belief)
(Decision)-[:RELIED_ON]->(Belief)
(Action)-[:EXECUTES]->(Decision)
(Source)-[:MIRRORS]->(Source)
(Rule)-[:LEARNED_FROM]->(Incident)
Enter fullscreen mode Exit fullscreen mode

Two details do most of the work:

  • MIRRORS links a source that copies another (a scrape of the same email, a syndicated post). Without it, copies look like independent confirmation.
  • jid on DERIVED_FROM groups premises into justifications. Edges with the same jid are AND-premises; different jids are alternative justifications. This is how the graph can say "this belief has two independent reasons to exist."

What the Guardian agent does

A Guardian agent (Gemini function calling over MCP tools) picks tools. The graph computes every answer; the LLM only chooses and narrates.

check_independence collapses mirrors and compares root origins per justification:

MATCH (b:Belief {id:$b})-[d:DERIVED_FROM]->(o:Observation)-[:FROM]->(s:Source)
OPTIONAL MATCH (s)-[:MIRRORS*0..3]->(root:Source)
WHERE NOT (root)-[:MIRRORS]->()
RETURN d.jid AS justification, collect(DISTINCT root.id) AS origins
Enter fullscreen mode Exit fullscreen mode

In our demo, both "confirmations" resolve to one origin. The badge flips from confirmed by 2 sources to 1 independent origin.

blast_radius is a forward traversal from the flagged source across agents, returning every contaminated belief, decision and action with hop counts.

find_chokepoint finds the one memory where cutting the path stops the infection from reaching the payment.

quarantine_and_repair runs truth maintenance: a belief survives if any justification still has all its premises intact. In the demo, the merged vendor profile keeps the facts that came from a signed invoice, loses only the poisoned bank details, and the payment is blocked.

learn_rule / pre_action_guard writes a rule node ("block payment claims with fewer than 2 independent origins") and checks it before any action runs. When the attacker replays the same claim through a new mirror, the guard blocks it before execution.

Why this needs a graph

We asked ourselves the hard question: could this be PostgreSQL plus embeddings?

  • Embeddings give similarity. They cannot say which belief was derived from which observation.
  • A recursive SQL query can do a simple taint traversal. But independence checks (disjoint root sets after collapsing mirrors), chokepoint analysis, and fixpoint repair over alternative justifications are natural graph operations and awkward in SQL.
  • FalkorDB multigraph gives us one isolated memory graph per tenant, which matters when agents serve different customers.

Take FalkorDB out and Patient Zero stops being able to explain, repair, or defend anything. It becomes a chatbot with memory.

What we built

  • A FalkorDB graph with a deterministic attack scenario plus live agent writes through MCP [confirm]
  • Seven Guardian tools backed by Cypher [confirm which ones are finished]
  • An animated dashboard that shows the infection spreading hop by hop, with a "Show the Cypher" panel so every claim is checkable
  • A learned guard rule that blocks a replay attack

What was hard

The trickiest part was expressing "survives if any justification is intact" in a graph. Putting a justification id on DERIVED_FROM edges and running a small fixpoint loop over Cypher reads gave us truth maintenance without leaving the graph for the core reads.

The second challenge was making independence honest. The moment we modeled MIRRORS explicitly, false corroboration became visible instead of invisible.

What's next

  • Real integrations: email, ticketing, payments
  • A time scrubber to replay how memory looked at any moment
  • A vulnerability scan using centrality to flag load-bearing, single-origin beliefs before an attack

Top comments (0)