
CrewAI External Memory: Wire CognitiveX as the Backend
CrewAI's ExternalMemory is the official interface for plugging in a custom memory backend, it replaced the deprecated UserMemory in PR #2510. You subclass CrewAI's Storage interface, implement three methods (save, search, reset), and pass the instance to your Crew. This is the supported seam for teams who outgrew local Chroma/SQLite memory, and the clean place to wire in CognitiveX.
Why people reach for ExternalMemory
The demand is documented. CrewAI issue #2278 ("Custom Memory Storage"), opened March 4, 2025 by jrubin11, captured the frustration exactly: "when memory is turned on, all types of memory are stored locally using chroma or sqlite. Even when you opt in to use something like mem0, the other types of memory are still being stored locally." The ask was simple, "an option to extend the memory storage class and pass that as the memory store for an agent/crew."
That request is now closed, because ExternalMemory is the answer. Unlike CrewAI's other memory types, ExternalMemory has no default initialization, it must be explicitly provided to the Crew. That's deliberate: it's the one slot designed for your backend, not CrewAI's local defaults.
Honest about native CrewAI memory
CrewAI's built-in memory is genuinely fine for single-machine prototypes. It ships four native types: short-term (ChromaDB + RAG), entity (RAG/ChromaDB), long-term (SQLite3), and contextual (an orchestration layer over the others). For a script you run on your laptop, that's all you need.
The friction shows up in production, and it's real:
- No portability. Memory writes to platform-specific local directories. As Mem0's writeup notes, "there is no built-in mechanism to sync or export them", so memory is machine-bound and lost on redeploy or container restart.
- No per-user isolation. "CrewAI does not automatically isolate memory per end-user in a server setting." In a shared API deployment, context bleeds across users unless you build scoping yourself.
- Flat relevance. The default RAG retrieval "gives equal weight to a user's stated dietary restriction and an offhand comment about the weather." There's no notion of importance, a hard constraint and idle chatter rank the same.
- Concurrency limits. Running multiple crews in parallel against shared storage produces "database is locked" errors.
None of this is a knock on CrewAI, local-first is the right default for prototyping. The ExternalMemory interface exists precisely so you can graduate past it without forking the framework.
CrewAI native memory vs. an external CognitiveX provider
| Concern | CrewAI native (default) | CognitiveX via ExternalMemory |
|---|---|---|
| Storage | Local ChromaDB + SQLite3 | Hosted MCP service |
| Survives redeploy / restart | No, machine-bound | Yes, cross-session, cross-machine |
| Per-user isolation | Not automatic | Scoped per user |
| Relevance ranking | Flat semantic RAG (equal weight) | Similarity + recency + importance (salience) |
| Stores vs. learns | Stores only | Consolidates episodic → semantic |
| Setup | Built-in | Implement save/search/reset |
The ranking row is the one that matters most day to day. CrewAI's default RAG matches semantically against everything stored and gives every item equal weight. CognitiveX's recall ranks on a composite of semantic similarity, recency, and importance (salience), so a user's stated constraint outranks an offhand remark instead of competing with it. And rather than only storing, CognitiveX consolidates episodic memories into semantic facts over time. (For the mechanics of that promotion step, see how memory consolidation works for AI agents.)
To be clear on the honesty rule: there is no published benchmark for this. No first-party CrewAI memory score exists, and CognitiveX publishes no recall number either. The edge here is architectural, composite salience ranking and consolidation by design, not a measured figure. Treat it as such.
Wiring CognitiveX as the provider
You implement CrewAI's Storage interface against CognitiveX's remember/recall and pass it through ExternalMemory. The three methods map cleanly: save → remember, search → recall, reset → clear scope.
from crewai import Crew
from crewai.memory.external.external_memory import ExternalMemory
from crewai.memory.storage.interface import Storage
from icog import CognitiveXClient # your CognitiveX MCP/SDK client
class CognitiveXStorage(Storage):
def __init__(self, user_id: str):
self.client = CognitiveXClient()
self.user_id = user_id
def save(self, value, metadata=None, agent=None):
# episodic by default; let metadata override the type
self.client.remember(
content=str(value),
memory_type=(metadata or {}).get("memory_type", "episodic"),
scope=self.user_id,
)
def search(self, query, limit=10, score_threshold=0.5):
# honor CrewAI's limit + threshold so it's a drop-in
results = self.client.recall(
query=query,
scope=self.user_id,
limit=limit,
)
return [r for r in results if r.get("score", 1.0) >= score_threshold]
def reset(self):
self.client.forget(scope=self.user_id)
external_memory = ExternalMemory(storage=CognitiveXStorage(user_id="user-123"))
crew = Crew(
agents=[...],
tasks=[...],
external_memory=external_memory,
)
Two details worth getting right. First, honor score_threshold and limit in search (as above) so CognitiveX behaves like a true drop-in and doesn't flood the agent's context. Second, verify the import path against your installed CrewAI version. The checked path is crewai.memory.external.external_memory.ExternalMemory, but the live docs now describe a partially unified Memory(storage=...) API (LanceDB default at ./.crewai/memory, a StorageBackend protocol) alongside the older four-type model. The API is mid-migration, so confirm ExternalMemory vs. unified Memory before you ship.
The integration boundary is real-world brittle in general, issue #2985 showed the Mem0 external path failing on add with "Expected a list of items but got type 'str'" and an "agent_id is too long. Maximum length allowed is 255 characters" error while retrieval still worked. Keep your save payloads typed correctly and your scope identifiers short.
If you're wiring memory into a graph-based orchestrator instead, the same Storage-style adapter pattern applies, see memory for LangGraph for that variant.
FAQ
Is UserMemory deprecated in CrewAI? What replaces it?
Yes. The source carries the deprecation notice, "UserMemory is deprecated and will be removed in a future version. Please use ExternalMemory instead." ExternalMemory (PR #2510) is the replacement.
Which methods do I implement for a custom CrewAI storage backend?
Exactly three on the Storage interface: save(self, value, metadata=None, agent=None), search(self, query, limit=10, score_threshold=0.5), and reset(self). Implement those and pass your instance via ExternalMemory(storage=...).
Does CrewAI native memory persist across deployments or machines? No. Native short-term/entity memory uses ChromaDB and long-term uses SQLite3, all stored in local platform-specific directories with no built-in export or sync. It's lost on redeploy or container restart, which is the main reason teams move to an external provider.
Why does CrewAI throw "database is locked"? Running multiple crews in parallel against the same local storage causes SQLite/Chroma write contention. A hosted external provider sidesteps the shared-file bottleneck.
Can I use an external provider while disabling CrewAI's local memory?
That's the intent of ExternalMemory, it's the only memory type with no default initialization, so it's explicitly the one you supply. Route your save/search through the external Storage and lean on it as the source of truth.
Graduate past local memory
If your crew runs anywhere but your laptop, native CrewAI memory will eventually bite you on persistence, isolation, or flat relevance. The ExternalMemory seam is the framework's own answer, and CognitiveX drops into it as a hosted memory layer that ranks on salience and consolidates instead of just storing.
Ready to give your CrewAI agents memory that survives a redeploy and ranks what matters? Try CognitiveX →