// lesson: shared-state
Shared State and What the Frameworks Give You
Everything your team passes around travels hand to hand: run_pipeline
threads one string from agent to agent, the critic loop passes drafts and
feedback, the router hands one task to one agent. That's message passing,
and it has a big architectural rival: the blackboard (LangGraph calls
its version graph state, CrewAI has shared memory) โ a shared store,
often just a dict, that every agent can read and write:
board = {"task": task}
board["research"] = researcher(board["task"])
board["draft"] = writer(board["research"])
board["verdict"] = critic(board["draft"])
The trade-offs cut cleanly:
- Message passing makes dataflow explicit โ you can read
run_pipelineand know exactly what the writer sees, which is why its unit tests were five lines. The cost: the plumbing must anticipate what each agent needs; when stage 4 suddenly needs stage 1's output, you're re-threading signatures. - The blackboard makes sharing free โ any agent can look at anything,
which fits workflows where you can't predict who needs what. The cost is
the same as any global state: hidden coupling (which agents actually
read
board["research"]? grep and pray), ordering hazards (read a key before its writer ran and you get aKeyErrorat best, a silently stale value at worst), and โ with concurrent agents โ races.
A battle-tested compromise shows up in serious systems, and you already
built it: keep the handoffs as messages, and keep an append-only
transcript on the side. Your run_pipeline transcript is exactly that โ
shared visibility for debugging and audit without shared mutable state
for logic. If you take one design rule from this lesson: reach for messages
first; adopt a blackboard when the wiring genuinely can't be predicted; and
never let agents communicate through state that isn't also in the
transcript, or you'll debug conversations you can't see.
So what do LangGraph and CrewAI actually sell you? Now you can read their docs as a checklist of things you've written:
- LangGraph: your functions become nodes;
run_pipelineis a chain of edges; the critic loop is a cycle with a termination condition (yourmax_roundsreappears as a recursion limit โ the same infinite-loop insurance with a different name);routeis a conditional edge; the blackboard is a typed state object passed to every node. What it adds beyond the vocabulary: checkpointing (pause and resume a long workflow), streaming, human-in-the-loop interrupts, and visualization. - CrewAI:
make_agentis anAgent(role, goal, backstory โ a structured system prompt); a pipeline of tasks is aCrewwithProcess.sequential; the router-in-charge isProcess.hierarchicalwith a manager LLM. What it adds: a library of ready-made tool integrations, memory, and conventions so teams stop reinventing role prompts.
Use them when you need what they add โ durable long-running workflows, their integrations, their observability. Skip them when a hundred lines of functions you fully understand will do. Either way, you now know what's inside the box, because you built the box.
One piece remains: assembling the whole machine โ pipeline in, critic loop on the result, bounded, with a full transcript out โ as a single function. That's the final challenge.