CrewAI Tutorial (Python): persisting agent state for beginners

By Cyprian AaronsUpdated 2026-04-21
crewaipersisting-agent-state-for-beginnerspython

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, and Crew in 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

  1. 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))
  1. 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,
)
  1. 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,
)
  1. 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)
  1. Put everything together in one executable script so you can rerun it and see persistence working. On each run, the runs counter increases and previous outputs stay available in agent_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, and open_questions instead 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

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

Related Guides