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
- Shared
bank_idacross unrelated crews mixes memory. Use unique IDs per project. - Huge task outputs increase retain latency. Tighten
expected_output. budget:"low"for speed,"high"for depth.- Async loops: use
AtulyaStorage/AtulyaReflectTool, not raw client calls from CrewAI's loop.
Next steps
- CrewAI integration docs
- Atulya Cloud to skip self-hosting
- Tags on retain /
recall_tagsfor scoped memory - Control plane UI to inspect facts and mental models