CrewAI Tutorial (Python): persisting agent state for beginners
This tutorial shows you how to persist CrewAI agent state in Python so your agents can remember what happened across runs. You need this when you want resumable workflows, auditability, or a simple way to keep context without rebuilding everything from scratch.
What You'll Need
- •Python 3.10+
- •
crewai - •
python-dotenv - •An OpenAI API key
- •Basic familiarity with
Agent,Task, andCrewin CrewAI - •A local project folder where you can create a small state file
Install the packages first:
pip install crewai python-dotenv
Create a .env file with your API key:
OPENAI_API_KEY=your_openai_api_key_here
Step-by-Step
- •Start by creating a simple project structure and loading your environment variables. For beginner-friendly persistence, we’ll store agent state in a JSON file on disk.
import json
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
STATE_FILE = Path("agent_state.json")
def load_state():
if STATE_FILE.exists():
return json.loads(STATE_FILE.read_text())
return {"runs": 0, "notes": []}
def save_state(state):
STATE_FILE.write_text(json.dumps(state, indent=2))
- •Next, define an agent that uses the stored state as part of its context. The key idea is that CrewAI agents are stateless by default, so you pass persisted data into the task prompt each time you run.
from crewai import Agent
researcher = Agent(
role="Research Assistant",
goal="Summarize the user's request using prior run context",
backstory="You keep track of previous runs and use them to improve output.",
verbose=True,
)
- •Now create a task that injects the saved state into the prompt. This is the practical persistence layer for beginners: load state before execution, then include it in the task description so the agent can continue from where it left off.
from crewai import Task
state = load_state()
task = Task(
description=f"""
You are continuing from a previous session.
Persisted state:
{json.dumps(state, indent=2)}
User request:
Write a short summary of what has changed since the last run.
""".strip(),
expected_output="A concise summary referencing prior context.",
agent=researcher,
)
- •Wrap the agent and task in a crew, run it, then update the stored state with the result. This gives you a repeatable pattern: read state, execute, write back state.
from crewai import Crew, Process
crew = Crew(
agents=[researcher],
tasks=[task],
process=Process.sequential,
verbose=True,
)
result = crew.kickoff()
state["runs"] += 1
state["notes"].append(str(result))
save_state(state)
print(result)
- •Put everything together in one executable script so you can rerun it and see persistence working. On each run, the
runscounter increases and previous outputs stay available inagent_state.json.
import json
from pathlib import Path
from dotenv import load_dotenv
from crewai import Agent, Task, Crew, Process
load_dotenv()
STATE_FILE = Path("agent_state.json")
def load_state():
if STATE_FILE.exists():
return json.loads(STATE_FILE.read_text())
return {"runs": 0, "notes": []}
def save_state(state):
STATE_FILE.write_text(json.dumps(state, indent=2))
state = load_state()
researcher = Agent(
role="Research Assistant",
goal="Summarize the user's request using prior run context",
backstory="You keep track of previous runs and use them to improve output.",
verbose=True,
)
task = Task(
description=f"""
Persisted state:
{json.dumps(state, indent=2)}
User request:
Explain what this app has learned from previous runs.
""".strip(),
expected_output="A concise explanation using prior context.",
agent=researcher,
)
crew = Crew(agents=[researcher], tasks=[task], process=Process.sequential, verbose=True)
result = crew.kickoff()
state["runs"] += 1
state["notes"].append(str(result))
save_state(state)
print(result)
Testing It
Run the script once and inspect agent_state.json. You should see "runs": 1 and one entry in notes. Run it again and confirm that "runs" increments to 2 and the new output is appended instead of replacing the old one.
If you want a quick sanity check, delete agent_state.json and rerun the script. The app should recreate it cleanly with an empty starting state.
This is not full memory inside CrewAI itself; it is durable application-level state that you control. That makes it easier to debug and safer for production workflows where you need explicit persistence behavior.
Next Steps
- •Add structured memory fields like
customer_id,last_summary, andopen_questionsinstead of storing only raw notes. - •Move persistence from JSON files to SQLite or Postgres when you need multi-user or multi-process support.
- •Explore CrewAI tools and callbacks so agents can write state changes only after successful task completion.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit