DEV Community

Mohammed Rafay
Mohammed Rafay

Posted on Originally published at memorysync.hashnode.dev

Persistent memory for CrewAI 1.x: keep crew memory across runs and redeploys

Disclosure: I'm Mohammed, founder of MemorySync. I drafted this article with AI assistance and reviewed it for accuracy against the official MemorySync and CrewAI docs. The code is adapted from the docs and I haven't run it.

CrewAI 1.x replaced its old short-term, long-term and entity memory classes with one Memory class. Turn it on with memory=True and the crew does the work for you: after each task it extracts discrete facts from the output and stores them, and before each task the agent recalls relevant context and injects it into the prompt (CrewAI memory docs).

The part that catches people is where that memory lives. By default it's LanceDB, stored under ./.crewai/memory (or $CREWAI_STORAGE_DIR/memory). That's fine on a laptop. It's a problem when:

  • your crew runs in a container whose filesystem is thrown away on every deploy,
  • two services run the same crew and should learn from each other, or
  • you want each of your customers to have their own memory, not one shared folder.

CrewAI's answer is a pluggable storage layer: implement the StorageBackend protocol and pass it to Memory(storage=...). This tutorial uses MemorySync's backend for that, plus the two extras the package ships: agent tools and a context helper for task descriptions.

What you'll set up

  1. A crew whose automatic save and recall loop runs against a hosted store instead of local files.
  2. A clear choice of who owns the memory: one crew, or one end user.
  3. Optional: tools so an agent can decide to store or look something up itself.
  4. Optional: a recall block you paste into a task description.

Install

pip install crewai-memorysync
Enter fullscreen mode Exit fullscreen mode

Per the MemorySync CrewAI guide, it needs CrewAI 1.0+ (the unified Memory system) and Python 3.10+. On an older CrewAI the import fails with a message naming the fix. Set MEMORYSYNC_API_KEY in your environment, or pass api_key explicitly, and keep it in server-side code.

One thing that doesn't change: CrewAI still runs its own LLM analysis and its own embedder. The backend receives a query embedding from CrewAI, so whatever embedder you've configured (OpenAI's text-embedding-3-large by default, per CrewAI's docs) still needs its credentials.

Step 1: point the crew's memory at the backend

from crewai import Agent, Crew, Task
from crewai.memory import Memory
from crewai_memorysync import MemorySyncStorage

crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, write_task],
    memory=Memory(
        storage=MemorySyncStorage(user_id="support-crew"),
    ),
)

crew.kickoff()
Enter fullscreen mode Exit fullscreen mode

That's the whole change. You don't add search-and-paste steps to your tasks: CrewAI keeps driving saves and recalls, and the records now go to MemorySync. Per the guide, they survive redeploys and are shared by every service that uses the same user_id.

If you'd rather not pass the backend around, register it once at startup and refer to it by name:

from crewai.memory import Memory
from crewai_memorysync import register_memorysync

register_memorysync(user_id="support-crew")   # once, at startup

memory = Memory(storage="memorysync")          # anywhere in the process
Enter fullscreen mode Exit fullscreen mode

The guide notes that unknown storage names still go to CrewAI's built-ins, so storage="lancedb" elsewhere in the same process keeps working.

Step 2: decide who owns the memory

user_id is the memory owner, and it's the most important choice in this setup:

  • One id per crew (like "support-crew" above) gives the crew a shared knowledge base. Everything any run learns is available to the next run, on any machine.
  • One id per end user gives each customer their own memory. A crew working for customer A doesn't see what it learned for customer B.

My rule of thumb: if the crew learns facts about a person, use that person's id, taken from your own authenticated user record. If it learns facts about the work (your stack, your product, your process), a crew-level id is the right shape. Don't use a session or run id here. A new id is a new, empty memory.

Step 3: check the loop end to end

You normally never call recall yourself, because agents recall as they work. But after a first run it's worth checking that something was actually stored:

matches = memory.recall("what stack does the team use?", depth="shallow")
for match in matches:
    print(match.score, match.record.content, match.record.scope)
Enter fullscreen mode Exit fullscreen mode

According to the guide, scope prefixes, category and metadata filters and scores behave like the built-in LanceDB backend, and records keep their scopes (for example /agent/researcher), categories, importance and sources through a round trip. If you're debugging, attach_memory_logging logs CrewAI's memory save and query events as they happen.

Two behaviours worth knowing before production:

  • Replays don't double-store. CrewAI runs saves on a background executor, so replays happen. The guide says saving an identical record again stores nothing twice, and an update replaces the previous version in place.
  • Failures are loud. CrewAI's executor silently drops RuntimeError, so the package never raises one. Failures surface as typed errors instead of saves that quietly vanish.

Step 4 (optional): let an agent manage memory itself

The automatic loop covers most cases. When you want an agent to explicitly decide "remember this" or "look that up", give it the five tools:

from crewai import Agent
from crewai_memorysync import create_memorysync_tools

agent = Agent(
    role="Personal assistant",
    goal="Help using what you know about the user",
    backstory="You remember the user's preferences.",
    tools=create_memorysync_tools(user_id="customer-7"),
)

# For agents you don't fully trust: search and list only
read_only_tools = create_memorysync_tools(user_id="customer-7", read_only=True)
Enter fullscreen mode Exit fullscreen mode

The tools are add_memory, search_memory, list_memories, update_memory and delete_memory. They never raise: errors come back as readable strings, so a tool failure can't abort a task. Memory text can't be edited, so update_memory changes tags and importance only. They're the same names and behaviour as the MemorySync LangChain tools, which helps if an agent moves between frameworks.

Step 5 (optional): put known context in a task description

For a task that should start from what you already know about a user, there's a one-line helper:

from crewai import Task
from crewai_memorysync import get_crew_context

context = get_crew_context("travel preferences", user_id="customer-7")

task = Task(
    description=f"Plan the trip.\nKnown preferences:\n{context or 'None yet.'}",
    expected_output="An itinerary honouring every stated preference.",
    agent=planner,
)
Enter fullscreen mode Exit fullscreen mode

It returns an empty string for a new user. That's a normal state, not an error, so give it a fallback like the or 'None yet.' above (my addition to the guide's example).

Resetting memory without wiping everything

crew.reset_memories() can end up calling reset() with no scope, which would erase everything that user_id owns. The backend refuses that by default:

storage = MemorySyncStorage(user_id="support-crew")

storage.reset()                      # refused: raises ValueError mentioning allow_full_reset
storage.reset("/agent/researcher")   # scoped resets always work

# Opt in only when a full wipe is really intended:
MemorySyncStorage(user_id="support-crew", allow_full_reset=True).reset()
Enter fullscreen mode Exit fullscreen mode

And if a delete removes nothing while matching records exist, it raises MemorySyncDeleteRefusedError instead of pretending it worked. For a crew that handles personal data, I'd want that to be loud too.

Recap

  1. pip install crewai-memorysync and set MEMORYSYNC_API_KEY.
  2. Memory(storage=MemorySyncStorage(user_id=...)) on your crew, or register_memorysync() once.
  3. Pick the owner: one id per crew to share, one per end user to keep memory separate.
  4. Check a first run with memory.recall(...).
  5. Add tools or get_crew_context only where an agent or task needs them.

Sources

  • MemorySync CrewAI Memory guide: docs.memorysync.io/guides/crewai
  • CrewAI memory docs: docs.crewai.com/en/concepts/memory
  • PyPI: crewai-memorysync 1.1.0

Try it

If you want to see the save, reload and recall loop before wiring up a crew, the MemorySync playground runs it in the browser with each API call shown: memorysync.io/try.

Top comments (0)