6 Building complex flows
This chapter covers
- Choosing Flows over a single crew
- Typed Pydantic state and the @start / @listen / @router primitives
- Fan-out, fan-in, and retry-via-router
- @persist for crash-safe resume
- Real Gmail and Slack providers behind one switch
If you have ever worked a support inbox on a busy Monday morning, you know what it looks like: fifty unread tickets spread across billing disputes, broken dashboards, feature requests, outright spam, and the occasional threatening email from a customer who has been waiting months for a response.
A single crew with one classifier agent and one responder might hold up for a week, but the first unusual edge case will break it. A real system needs a control plane—something that can gather context, route by category, retry when an upstream service returns an error, escalate when things stay broken, and resume cleanly after a crash.
That control plane is what CrewAI calls a Flow.
A Flow does not replace crews; it orchestrates them. A single Flow can call a standalone agent, a full crew, a plain Python function, or an external HTTP service, whichever fits the step best. Most production agentic applications end up with this layered shape. Even non-CrewAI systems like Claude Code are built on a similar workflow underneath, with conversation history, compaction events, tool retries, and error handling. The primitives map directly onto what we are about to build.