{"slug": "loops-and-beads-orchestrating-ai-agents-with-postman", "title": "Loops and beads: orchestrating AI agents with Postman", "summary": "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.", "body_md": "# Loops and beads: orchestrating AI agents with Postman\n\nEvery 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.\n\nI’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.\n\nThe [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.\n\n## What loops and beads mean in code\n\nA *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.\n\nA *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.\n\nThe plugin’s own command set is already bead-shaped. `/postman:test`\n\nand `/postman:security`\n\ndon’t depend on each other’s output. Neither does `/postman:docs`\n\n. 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.\n\n## Building the same agent twice\n\nTo 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.\n\nThe 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.\n\n### The loop version\n\nThe loop agent gives Claude two tools and lets it decide when to call them:\n\n```\nTOOLS = [\n    {\n        \"name\": \"get_collection_summary\",\n        \"description\": \"Fetch a Postman Collection by ID and summarize its request count and auth type.\",\n        \"input_schema\": {\n            \"type\": \"object\",\n            \"properties\": {\"collection_id\": {\"type\": \"string\"}},\n            \"required\": [\"collection_id\"],\n        },\n    },\n    {\n        \"name\": \"run_monitor\",\n        \"description\": \"Trigger a Postman Monitor run by ID and return its pass/fail summary.\",\n        \"input_schema\": {\n            \"type\": \"object\",\n            \"properties\": {\"monitor_id\": {\"type\": \"string\"}},\n            \"required\": [\"monitor_id\"],\n        },\n    },\n]\n```\n\nThe loop itself is short. Call the model, check if it asked for a tool, run the tool, append the result, repeat:\n\n```\nwhile True:\n    response = await anthropic.messages.create(\n        model=MODEL, max_tokens=1024, tools=TOOLS, messages=messages\n    )\n    messages.append({\"role\": \"assistant\", \"content\": response.content})\n\n    if response.stop_reason != \"tool_use\":\n        break\n\n    tool_results = []\n    for block in response.content:\n        if block.type == \"tool_use\":\n            result = await call_tool(block.name, block.input)\n            tool_results.append(\n                {\"type\": \"tool_result\", \"tool_use_id\": block.id, \"content\": json.dumps(result)}\n            )\n    messages.append({\"role\": \"user\", \"content\": tool_results})\n```\n\nThis 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.\n\n### The bead version\n\nThe bead version replaces the loop with an explicit graph. A bead is a small dataclass:\n\n```\n@dataclass\nclass Bead:\n    name: str\n    run: Callable[[dict, dict], Awaitable[Any]]\n    deps: tuple[str, ...] = ()\n```\n\nAnd 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:\n\n``` php\nasync def run_graph(beads: list[Bead], context: dict) -> dict[str, Any]:\n    done: dict[str, Any] = {}\n    remaining = {b.name: b for b in beads}\n\n    while remaining:\n        ready = [b for b in remaining.values() if all(d in done for d in b.deps)]\n        if not ready:\n            raise RuntimeError(f\"Unmet bead dependencies: {list(remaining)}\")\n\n        results = await asyncio.gather(*(b.run(context, done) for b in ready))\n        for bead, result in zip(ready, results):\n            done[bead.name] = result\n            del remaining[bead.name]\n\n    return done\n```\n\nThe graph for this agent has four beads. `classify_intent`\n\nruns 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`\n\nand `run_monitor`\n\nboth depend only on `classify_intent`\n\n, so they run at the same time. `build_report`\n\ndepends on both and merges their output into an answer:\n\n```\nbeads = [\n    Bead(\"classify_intent\", bead_classify_intent),\n    Bead(\"fetch_collection\", bead_fetch_collection, deps=(\"classify_intent\",)),\n    Bead(\"run_monitor\", bead_run_monitor, deps=(\"classify_intent\",)),\n    Bead(\"build_report\", bead_build_report, deps=(\"fetch_collection\", \"run_monitor\")),\n]\ndone = await run_graph(beads, context)\n```\n\nFour beads, three layers, and the middle layer runs both of its beads in parallel instead of waiting on itself.\n\n## Running the comparison\n\nThe script has a `--demo`\n\nflag 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:\n\n```\npip install anthropic httpx python-dotenv\necho \"ANTHROPIC_API_KEY=sk-ant-...\" > .env\n\npython3 postman_loops_and_beads.py --demo --pattern compare\n```\n\nOn my machine that prints something close to this:\n\n```\n=== loop pattern ===\nYour collection has 14 requests using bearer auth, and the monitor run passed all 22 assertions.\n\n[loop] wall clock: 3.02s\n\n=== beads pattern ===\nYour collection (14 requests, bearer auth) looks fine, and the monitor run passed all 22 assertions with no failures.\n\n[beads] wall clock: 1.83s\n\nbeads finished faster (loop: 3.02s, beads: 1.83s) because independent beads ran in parallel.\n```\n\nThe 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`\n\nand `run_monitor`\n\nran 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.\n\nDrop `--demo`\n\nand 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`\n\nfile:\n\n```\necho \"POSTMAN_API_KEY=PMAK-...\" >> .env\n\npython3 postman_loops_and_beads.py --pattern beads \\\n  --collection <your_collection_id> --monitor <your_monitor_id>\n```\n\n## Where each pattern fits with the plugin\n\nI wouldn’t rewrite every agent as a bead graph. The two patterns solve different problems, and the plugin’s own commands split cleanly along that line.\n\nA loop still makes sense for anything genuinely conversational, where you don’t know the next step until you see the result of the last one. Debugging a failing test with `/postman:test`\n\n, following up on findings from a `/postman:security`\n\naudit, or iterating on client code with `/postman:sync`\n\nall fit that shape. The model needs room to change direction.\n\nA bead graph pays off once you know the shape of the work ahead of time and some of it doesn’t depend on the rest. `/postman:test`\n\nand `/postman:security`\n\ndon’t read each other’s output. Neither does checking a spec against the [agent readiness analyzer](https://github.com/Postman-Devrel/agent-skills) that scores APIs across eight pillars. An agent that runs “test, audit, and score” as three independent beads finishes in roughly the time of the slowest one, not all three added together. And if the security audit bead fails, you retry that bead alone instead of rerunning tests that already passed. That’s the granular re-entry the beads post calls out, and it matters more as the number of steps grows.\n\n## Try it yourself\n\nClone the script and run it against a real Postman workspace:\n\n```\ngit clone https://github.com/quintonwall/loops-and-beads.git\ncd loops-and-beads\npip install anthropic httpx python-dotenv\ncp .env.example .env   # then fill in your own keys\n```\n\nThen try changing the question. Ask it to only check the monitor, and watch `classify_intent`\n\nskip the collection lookup entirely. Add a third bead, maybe a call to the [agent readiness](https://github.com/Postman-Devrel/agent-skills) checks, depending only on `classify_intent`\n\n, and it joins the parallel layer for free. That’s the part of beads that’s easy to miss from the outside: adding independent work doesn’t add latency. It adds another item to the same `asyncio.gather`\n\ncall.\n\nIf you haven’t set up the Postman plugin for Claude Code yet, [install it](https://github.com/Postman-Devrel/postman-claude-code-plugin) and run `/postman:setup`\n\nto authenticate. Once it’s running, try asking it to test and audit an API in the same message and watch which commands it fires off. You’ll start noticing which parts of your own agent workflows are secretly loops and which ones have been beads all along.\n\n## Resources\n\n[Two loops: building with AI agents](https://www.quintonwall.com/writing/two-loops-building-with-ai-agents)[Why beads are replacing loops in agents](https://www.quintonwall.com/writing/why-beads-are-replacing-loops-in-agents)[Postman plugin for Claude Code on GitHub](https://github.com/Postman-Devrel/postman-claude-code-plugin)[Announcing the Postman plugin for Claude Code](https://blog.postman.com/announcing-the-postman-plugin-for-claude-code/)[Postman MCP server setup docs](https://learning.postman.com/docs/developer/postman-api/postman-mcp-server/set-up-postman-mcp-server)[Model Context Protocol specification](https://modelcontextprotocol.io/specification/2025-06-18)[Postman API reference: collections](https://learning.postman.com/api-docs/api-reference/collections/get-collections)[Monitoring your API in Postman](https://learning.postman.com/docs/monitoring-your-api/intro-monitors)[Claude Messages API docs](https://platform.claude.com/docs/en/build-with-claude/working-with-messages)[Complete working example on GitHub](https://github.com/quintonwall/loops-and-beads)", "url": "https://wpnews.pro/news/loops-and-beads-orchestrating-ai-agents-with-postman", "canonical_source": "https://blog.postman.com/loops-and-beads-orchestrating-ai-agents-with-postman/", "published_at": "2026-08-14 16:00:00+00:00", "updated_at": "2026-08-14 16:17:50.613569+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "artificial-intelligence"], "entities": ["Postman", "Claude Code", "Postman MCP server", "Postman API", "Quinton Wall"], "alternates": {"html": "https://wpnews.pro/news/loops-and-beads-orchestrating-ai-agents-with-postman", "markdown": "https://wpnews.pro/news/loops-and-beads-orchestrating-ai-agents-with-postman.md", "text": "https://wpnews.pro/news/loops-and-beads-orchestrating-ai-agents-with-postman.txt", "jsonld": "https://wpnews.pro/news/loops-and-beads-orchestrating-ai-agents-with-postman.jsonld"}}