Skip to main content

CrewAI agents that remember between runs

· 2 min read

CrewAI's built-in memory works inside one kickoff(). When the process exits, context is gone. atulya-crewai implements CrewAI's Storage interface on top of Atulya banks so knowledge compounds across runs.

The problem​

Research crews, support crews, planning crews that run daily need memory that survives restarts. SQLite/RAG backends in CrewAI target single-run persistence, not months of accumulated facts.

Architecture​

CrewAI Crew
└─ ExternalMemory
└─ AtulyaStorage
├─ save() → retain
├─ search() → recall
└─ reset() → delete_bank + recreate

CrewAI calls save() after tasks and search() before tasks. Atulya extracts facts, entities, and graph links; recall uses multi-strategy retrieval + reranking.

Quick start​

pip install atulya-all atulya-crewai
export ATULYA_API_LLM_API_KEY=YOUR_KEY
atulya-api
from atulya_crewai import configure, AtulyaStorage
from crewai.memory.external.external_memory import ExternalMemory
from crewai import Agent, Crew, Task

configure(atulya_api_url="http://localhost:8888")

researcher = Agent(
role="Researcher",
goal="Find accurate information on the topic.",
backstory="Thorough researcher.",
llm="openai/gpt-4o-mini",
)

research_task = Task(
description="Research Rust for CLI tools.",
expected_output="Summary of Rust strengths for CLI.",
agent=researcher,
)

crew = Crew(
agents=[researcher],
tasks=[research_task],
external_memory=ExternalMemory(
storage=AtulyaStorage(
bank_id="research-crew",
mission="Track research findings and comparisons.",
)
),
)

crew.kickoff()

Second run on Go vs Rust: the crew recalls prior Rust research. Third run asking for a recommendation draws on both sessions.

Reflect tool​

reflect is not on the Storage interface; expose it as a tool:

from atulya_crewai import AtulyaReflectTool

reflect_tool = AtulyaReflectTool(
bank_id="research-crew",
budget="mid",
reflect_context="Helping a team evaluate languages.",
)

researcher = Agent(..., tools=[reflect_tool], ...)

Per-agent banks​

AtulyaStorage(bank_id="research-crew", per_agent_banks=True)
# → research-crew-researcher, research-crew-writer, ...

Or custom:

bank_resolver=lambda base, agent: f"{base}-{agent.lower()}" if agent else base

Pitfalls​

  1. Shared bank_id across unrelated crews mixes memory. Use unique IDs per project.
  2. Huge task outputs increase retain latency. Tighten expected_output.
  3. budget: "low" for speed, "high" for depth.
  4. Async loops: use AtulyaStorage / AtulyaReflectTool, not raw client calls from CrewAI's loop.

Next steps​