Loops and beads: orchestrating AI agents with Postman Postman's plugin for Claude Code, backed by the Postman MCP server, demonstrates two patterns for orchestrating AI agents: loops and beads, with beads enabling parallel execution of independent tasks. Developer Quinton Wall built the same agent twice against the Postman API, showing that a bead graph runs independent commands like /postman:test, /postman:security, and /postman:docs concurrently, while a loop processes them sequentially. The comparison highlights that beads are more efficient for tasks with known structure and independent steps. Loops and beads: orchestrating AI agents with Postman Every AI agent boils down to the same three moves: decide what to do, do it, look at the result. The part that matters is how you wire those moves together. Get the wiring wrong and a two-second task takes six. Get it wrong badly enough and a single stuck step takes the whole agent down with it. I’ve been thinking about this in terms of two patterns I wrote about separately: loops https://www.quintonwall.com/writing/two-loops-building-with-ai-agents and beads https://www.quintonwall.com/writing/why-beads-are-replacing-loops-in-agents . A loop is temporal repetition: call the model, run a tool, feed the result back, repeat until done. A bead is structural composition: a small unit of work with a defined input and output, wired into a graph alongside other beads. Loops are great for open-ended, conversational tasks. Beads are better once you know the shape of the work in advance and some of it can happen in parallel. The Postman plugin for Claude Code https://github.com/Postman-Devrel/postman-claude-code-plugin turned out to be a good place to see the difference firsthand. It ships eight commands, backed by the Postman MCP server https://learning.postman.com/docs/developer/postman-api/postman-mcp-server/set-up-postman-mcp-server , for syncing collections, generating client code, running tests, creating mocks, publishing docs, auditing security, and scoring API readiness. In this post I’ll build the same small agent twice against the Postman API https://learning.postman.com/api-docs/ , once as a loop and once as a bead graph, and show you the code so you can run both yourself. What loops and beads mean in code A loop agent is one conversation with the model that keeps going until the model says it’s done. You define a set of tools, hand the model a question, and every time it asks for a tool call, you run that tool and feed the result back in. Claude’s Messages API https://platform.claude.com/docs/en/build-with-claude/working-with-messages is stateless, so each turn resends the full conversation history, and the model decides one step at a time what happens next. That’s the ReAct pattern https://learning.postman.com/docs/postman-ai-agent-builder/overview/ most agent frameworks default to, and it’s a fine default: it’s simple, and the model can change its mind mid-task. A bead agent is a graph you define up front. Each bead is a function with a name, a job, and a list of dependencies. A bead only runs once its dependencies have finished, and beads with no dependency on each other run at the same time. Nothing here is unique to Postman or Claude. It’s closer to how you’d design a build pipeline or a data processing DAG than to a chat loop, and that’s exactly the point: once a task’s structure is known, you don’t need the model to rediscover it turn by turn. The plugin’s own command set is already bead-shaped. /postman:test and /postman:security don’t depend on each other’s output. Neither does /postman:docs . If an agent needs all three, running them one after another in a loop wastes time waiting on network calls that have nothing to do with each other. That’s the exact case beads are built for. Building the same agent twice To make the comparison concrete, I wrote one task two ways: “Is my API collection healthy?” The task needs two pieces of information, a summary of a Postman Collection https://learning.postman.com/api-docs/api-reference/collections/get-collections and the pass/fail result of a Postman Monitor https://learning.postman.com/docs/monitoring-your-api/intro-monitors run. Neither depends on the other. The full, runnable script is in postman loops and beads.py https://github.com/quintonwall/loops-and-beads/blob/main/postman loops and beads.py in the companion repo. I’ll walk through the parts that matter here, but grab the file if you want to run it against your own workspace. The loop version The loop agent gives Claude two tools and lets it decide when to call them: TOOLS = { "name": "get collection summary", "description": "Fetch a Postman Collection by ID and summarize its request count and auth type.", "input schema": { "type": "object", "properties": {"collection id": {"type": "string"}}, "required": "collection id" , }, }, { "name": "run monitor", "description": "Trigger a Postman Monitor run by ID and return its pass/fail summary.", "input schema": { "type": "object", "properties": {"monitor id": {"type": "string"}}, "required": "monitor id" , }, }, The loop itself is short. Call the model, check if it asked for a tool, run the tool, append the result, repeat: while True: response = await anthropic.messages.create model=MODEL, max tokens=1024, tools=TOOLS, messages=messages messages.append {"role": "assistant", "content": response.content} if response.stop reason = "tool use": break tool results = for block in response.content: if block.type == "tool use": result = await call tool block.name, block.input tool results.append {"type": "tool result", "tool use id": block.id, "content": json.dumps result } messages.append {"role": "user", "content": tool results} This works and it’s easy to follow. The catch is timing. Claude can only ask for one thing at a time in this setup, so it fetches the collection, waits for the result, then decides to run the monitor, and waits again. The two lookups never overlap even though nothing requires them not to. The bead version The bead version replaces the loop with an explicit graph. A bead is a small dataclass: @dataclass class Bead: name: str run: Callable dict, dict , Awaitable Any deps: tuple str, ... = And a graph runner that runs every bead whose dependencies are already done, one layer at a time, using asyncio.gather https://docs.python.org/3/library/asyncio-task.html asyncio.gather to run each layer concurrently: php async def run graph beads: list Bead , context: dict - dict str, Any : done: dict str, Any = {} remaining = {b.name: b for b in beads} while remaining: ready = b for b in remaining.values if all d in done for d in b.deps if not ready: raise RuntimeError f"Unmet bead dependencies: {list remaining }" results = await asyncio.gather b.run context, done for b in ready for bead, result in zip ready, results : done bead.name = result del remaining bead.name return done The graph for this agent has four beads. classify intent runs first, using a fast Haiku call to decide whether the question needs the collection lookup, the monitor run, or both, so a bead can skip its own work based on what an earlier bead decided. That’s the first-class branching the beads post talks about: the decision lives in the graph, not buried in a prompt. fetch collection and run monitor both depend only on classify intent , so they run at the same time. build report depends on both and merges their output into an answer: beads = Bead "classify intent", bead classify intent , Bead "fetch collection", bead fetch collection, deps= "classify intent", , Bead "run monitor", bead run monitor, deps= "classify intent", , Bead "build report", bead build report, deps= "fetch collection", "run monitor" , done = await run graph beads, context Four beads, three layers, and the middle layer runs both of its beads in parallel instead of waiting on itself. Running the comparison The script has a --demo flag that swaps the real Postman API calls for canned responses with realistic delay 1.2 seconds for the collection lookup, 1.8 seconds for the monitor run , so you can see the timing difference without a Postman API key: pip install anthropic httpx python-dotenv echo "ANTHROPIC API KEY=sk-ant-..." .env python3 postman loops and beads.py --demo --pattern compare On my machine that prints something close to this: === loop pattern === Your collection has 14 requests using bearer auth, and the monitor run passed all 22 assertions. loop wall clock: 3.02s === beads pattern === Your collection 14 requests, bearer auth looks fine, and the monitor run passed all 22 assertions with no failures. beads wall clock: 1.83s beads finished faster loop: 3.02s, beads: 1.83s because independent beads ran in parallel. The loop’s time is close to the sum of both simulated delays, 1.2 seconds plus 1.8 seconds. The bead graph’s time is close to the slower of the two, because fetch collection and run monitor ran together. That’s the same sum-or-slowest-operation tradeoff from the beads post https://www.quintonwall.com/writing/why-beads-are-replacing-loops-in-agents ‘s travel-brief example, measured here instead of described. Drop --demo and add real IDs to hit the live Postman API https://learning.postman.com/api-docs/ with your own credentials. Add your Postman API key to the same .env file: echo "POSTMAN API KEY=PMAK-..." .env python3 postman loops and beads.py --pattern beads \ --collection