Framework or Plain Loop? Four Questions That Actually Decide It
The core agent loop is under a hundred lines — that's never what a framework saves you. Four situational questions decide it, and the one about 3am debugging should carry the most weight.
The agent-framework decision usually gets made on vibes — either "frameworks are bloat" or "we shouldn't reinvent this" — and both camps ship things they regret. Four questions settle it faster than any feature comparison, because they're about your situation rather than the framework's capabilities.
First, the thing worth knowing before the questions: the core loop is genuinely small. Send messages plus tool specs, get back tool calls, execute them, append results, repeat until no tool calls. That is not the part a framework saves you. What frameworks provide is everything around it — retries, streaming, tracing, state persistence, provider abstraction, prebuilt integrations, and opinions about multi-agent structure. Evaluate the surroundings, not the loop.
1. Is your control flow linear, or does it branch on judgment?
Linear pipelines with fixed steps don't need an agent framework and often don't need an agent. If your flow is "extract, then validate, then write," ordinary code calling a model at two points is clearer than any orchestration abstraction, and it fails in ways your existing tooling already understands.
Branching that depends on what the model concluded — retry differently based on the error, escalate on low confidence, fan out over a discovered list — is where a framework's state handling starts earning its keep. If you find yourself writing your own scheduler, checkpointing, or resumption logic, that's the signal you've grown into one.
2. How many providers must you support, honestly?
Provider abstraction is the most-cited reason to adopt a framework and the least-often needed. Supporting one provider means the abstraction costs you indirection and buys nothing; tool-calling formats differ, but the adapter is a small amount of code you'd write once.
It flips when portability is a real requirement — a contractual one, a per-customer deployment, a cost strategy that routes different steps to different models. Then a maintained abstraction beats one you keep patching, since providers change formats on their own schedule.
3. Do you need the ecosystem, or three integrations?
Frameworks bundle connectors. If your agent needs a broad, shifting set of them, that bundle is real leverage.
If it needs three — your database, your ticket system, one internal API — you will write those three regardless. Nobody's prebuilt connector matches your schema, your auth, or your error semantics. ⚠️ The failure I'd watch for is adopting a framework for its integration catalog and then overriding every integration you use.
Worth noting: MCP shifts this question. Connecting tools through a standard protocol makes integrations portable across frameworks and across plain loops, which weakens "the catalog" as a reason to adopt any particular one.
4. Who debugs this at 3am, and what will they see?
This is the question that should carry the most weight, and it's usually asked last.
When a run goes wrong, someone needs the exact array sent to the model on the failing turn. In a plain loop that's one print away. In a framework it's however many layers of callbacks, middleware, and state machinery sit between your code and the API call — and the framework's own tracing may show you its abstractions rather than the raw request.
Frameworks with good tracing turn this into a strength: a trace viewer, replay, and structured logs are real work you'd otherwise build. Frameworks with poor tracing turn a ten-minute investigation into an afternoon. → Before adopting, deliberately break something and try to diagnose it. That exercise predicts your next year more accurately than the feature matrix.
A default that ages well
Start with a plain loop and a thin seam: put your provider call, your tool dispatch, and your context assembly each behind one function you own. Under a hundred lines, and you understand every part of it.
Adopt a framework when you hit a specific thing you don't want to build — durable execution across restarts, a real trace UI, human-in-the-loop approval flows with persistence, or multi-provider routing. Adopting to solve a named problem gets you a framework you use deliberately. Adopting on principle gets you one you fight.
✅ Signals you've outgrown the plain loop: you're building checkpoint/resume; you have three flavors of retry logic; you can't reconstruct why a run did what it did; you're writing your own approval queue.
❌ Signals a framework is costing you: you subclass more than you configure; the fastest way to understand a bug is reading framework source; upgrades break behavior you never touched; your "agent" is a linear pipeline in a graph API.
The takeaway
Nobody wins points for having written the loop. Frameworks are a trade of some transparency for a lot of infrastructure, and the trade is good exactly when you need that infrastructure. Answer the four questions for your actual system rather than the one you might have in two years, and revisit when the answers change.