Inspiration

Every AI assistant forgets you the moment the conversation ends. And the few that do remember? They blindly overwrite old facts with new ones, with no awareness that a contradiction just happened.

We wanted to build something that actually handles the messiest part of memory: conflict. What should an AI do when it "knows" you prefer working alone — but last week you said you thrive in teams? A human would notice the contradiction and think it through. ConflictMind does the same: it detects the conflict, argues both sides, and resolves them into a single coherent truth.


What it does

ConflictMind is a personal AI assistant that:

1. Remembers you — every conversation is summarized and stored as typed memories (semantic, episodic, procedural) in MongoDB Atlas with vector embeddings.

2. Detects contradictions — vector similarity search finds memories that conflict, and an LLM classifier filters out false positives before flagging a real conflict.

3. Debates itself — a structured three-step adversarial pipeline runs: Memory A makes its case → Memory B makes its case → a Gemini judge synthesizes a resolved memory.

4. Shows its reasoning — the full debate transcript is stored alongside the resolved memory. You can click any resolved node in the memory graph to see exactly how the conflict was settled.


How we built it

Agent layer: Google ADK (google-adk) with gemini-2.5-flash via Vertex AI. The agent uses two tools: a FunctionTool (store_memory) that calls our Flask backend to write memories with embeddings and trigger conflict detection, and an MCPToolset connecting to the MongoDB MCP server to directly query Atlas for relevant memories before every response.

Memory layer: MongoDB Atlas M0 with vector search. Memories are stored with text embeddings; retrieval is cosine similarity top-k. Conflict pairs are stored separately with full debate transcripts attached.

Conflict pipeline: Custom reconciler module:

detect (similarity threshold + LLM classifier)
  → debate (three sequential Gemini calls)
  → resolve (unified memory written back to Atlas)

Backend: Flask serves the frontend, wires the ADK session/run API, and exposes REST endpoints for memories, conflicts, and the D3 graph data.

Deployment: Dockerized on Google Cloud Run. The MongoDB MCP server is installed globally at Docker build time (npm install -g mongodb-mcp-server) rather than spawned per-request — a key fix that eliminated cold-start failures on Cloud Run.

Frontend: Vanilla JS + D3.js memory graph — nodes sized by confidence, colored by memory type, conflict edges in amber, resolved nodes in green. Clicking a node surfaces the full debate transcript.


Challenges we ran into

False positive conflicts. Cosine similarity alone (even at 0.85) flagged too many unrelated memories. We added an LLM classify_conflict() call inside the detection step to verify a conflict is real before saving a conflict pair.

Memory status poisoning. Our initial save_conflict_pair() marked both memories as status: "conflicted" immediately on write — which broke vector search, since it only queries status: "active" documents. Fix: status only updates after reconciliation completes, never on initial write.

Gemini API quota exhaustion. Daily quota limits on the AI Studio key hit us mid-demo. Switched to Vertex AI with application default credentials — more stable, no per-key quota ceiling.

Cloud Run deployment size. Initial builds were uploading ~194MB because large directories weren't excluded. Added a proper .gcloudignore to strip node_modules/, __pycache__/, test files, and the virtual environment.

ADK + MCP at runtime vs. build time. Running npx mongodb-mcp-server at runtime on Cloud Run caused cold-start timeouts. Moving the install to the Dockerfile and calling the binary directly fixed it.


Accomplishments that we're proud of

  • A working adversarial debate pipeline that produces genuinely nuanced memory reconciliations — not just "last write wins"
  • The memory graph visualization — watching conflict edges appear and resolve in real time is a compelling demo
  • Discovering the ADK + MongoDB MCP hard requirements mid-hackathon and pivoting without breaking the existing architecture — modular design paid off

What we learned

  • Memory systems are harder than chat systems. The interesting problems are all in the edges: false positives, status management, embedding drift.
  • Google ADK's MCPToolset + FunctionTool combination gives clean separation between read (MCP → Atlas find) and write (custom function → embeddings + conflict detection).
  • Vertex AI application default credentials are the right path for Cloud Run — no key rotation, no quota surprises.

What's next

  • User accounts — multi-user support with scoped memory namespaces
  • Memory aging — lower confidence on old memories so recent facts win ties without a full debate
  • Proactive reconciliation — surface unresolved conflicts to the user in-chat rather than only resolving in the background
  • Debate explainability UI — a dedicated panel showing the full debate transcript inline in the memory graph

Built with

google-adk · gemini-2.5-flash · vertex-ai · mongodb-atlas · mongodb-mcp-server · vector-search · flask · docker · google-cloud-run · d3.js · python

Built With

Share this project:

Updates