AI Infra
0%
Part XI · Chapter 85

Agents, Frameworks, and Sandboxes

AuthorChangkun Ou
Reading time~20 min

The agent architecture of Chapter 38, the harness of Chapter 41, and the authorization model of Chapter 56 meet in one engineering decision: how to buy and wire the runtime for an agent shipping in 2026. The useful choice is not a library ranking. It is a choice of loop archetype, tool protocol, sandbox boundary, and a default that is hard to regret.

2026-06-22T11:57:21.176444 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/
Figure 85.1. Schematic of sandbox choices by task freedom and containment. The dangerous corner is high freedom with weak containment, not merely high capability. Idealized placement, not measured data.

An agent runtime is three parts, and most of the 2026 confusion comes from conflating them:

  1. The framework / SDK is the loop. The model only emits tokens. To make it call a tool, read the result, decide the next step, remember earlier turns, hand work to another agent, pause for a human, and recover after a crash, you need a control loop and the plumbing around it.
  2. Model Context Protocol (MCP) is the wire protocol for tools. It is to tool integration what the OpenAI Chat Completions shape is to model calls: the common interface that lets one tool server be reused by every framework.
  3. The sandbox is the execution substrate. The moment an agent runs code, the safety story stops being about the model and becomes about the runtime. The sandbox is the isolated computer the code runs in.

The throughline is that the framework, the tools, and the box all keep secrets and model access outside, reaching in only through governed seams: a virtual key issued by a gateway for model access, a short-lived scoped token for a credential a provider will mint on demand, egress substitution for a static secret it will not (the box holds a placeholder, a proxy swaps in the real value toward allowed hosts), and a default-deny network for egress. Get that discipline right and the specific products become reversible choices.

As of mid-2026

Everything below is a dated snapshot (June 2026). Version numbers, prices, and "best for" verdicts move fast in this category. Treat rankings and specific figures as source-attributed and verifiable, not as timeless fact, and confirm current values on each project's own docs before you commit. The durable content is the categories and trade-offs, not the version strings.

Frameworks: the landscape

Feature checklists hide the real decision. The axis that matters is how the framework structures the agent loop, because that dictates what you can express, how much boilerplate you write, and where control lives. Five archetypes cover the field, and they map directly onto the loop structures of Chapter 38:

  1. Graph / state-machine (LangGraph, Google ADK, Pydantic AI's pydantic-graph). You declare nodes and edges; the runtime walks the graph, persists a typed State, and supports loops, parallel branches, conditional routing, and crash-resume from a checkpoint. Most expressive, most control, most boilerplate. The only archetype that natively handles "Agent A then B then back to A" and "B and C in parallel."
  2. Linear handoff chain (OpenAI Agents SDK). A small set of primitives; agents delegate by handing off the conversation, and the receiver sees the full transcript. Cyclic or parallel topologies must be modeled by hand. Fastest to a working agent.
  3. Harness / CLI engine (Claude Agent SDK). The loop is the Claude Code engine of Chapter 41: a real filesystem, bash, web search, and automatic context compaction (summarizing or dropping older turns to fit the context window) are built in, and you extend it with hooks, in-process MCP tools, and subagents. Unmatched for "a model working in a repo."
  4. Role / crew orchestration (CrewAI). You define specialist roles and goals; the crew collaborates. Natural when work decomposes into roles, less fine-grained than a graph.
  5. Model-first autonomous loop (AWS Strands). A system prompt plus tools, and the model drives. Least scaffolding, least deterministic control.

Tool and memory handling is the second axis, and MCP has flattened most of it. Tools are either native function tools (a decorated function whose signature becomes the schema) or MCP servers (external over stdio/HTTP, or in-process). Memory ranges from "the framework replays the message list each turn" (OpenAI Sessions, simplest) to "a durable, checkpointed State you can rewind" (LangGraph, Pydantic AI durable execution). The deciding question is whether you must survive a restart mid-task. If yes, you want a checkpointer, not a message list.

A comparison of the players

Versions and license claims below are as of June 2026 and attributed in Further reading. Where a "best for" verdict is the field's loose consensus rather than a vendor fact, read it as directional.

Name Loop archetype License / backer Pick it when Note
LangGraph Graph / state-machine MIT, LangChain Inc.; paid Platform for hosting The workflow is genuinely a graph: loops, parallel branches, approval gates, long-running, must survive crashes 1.0 GA reached; most control, most boilerplate. "Time travel" rewinds State to a prior checkpoint
OpenAI Agents SDK Linear handoff chain MIT, OpenAI You want the shortest path to a production agent of moderate complexity and a tiny primitive set over maximal control Provider-agnostic despite the name: 100+ models via Chat Completions / LiteLLM. Cyclic/parallel routing is hand-built
Claude Agent SDK Harness / CLI engine MIT, Anthropic; model usage billed via Claude API The agent is fundamentally Claude working over a filesystem/CLI: coding agents, repo automation, ops Renamed from Claude Code SDK in late 2025. Strongest MCP-native and lifecycle-hook story; in-process tools avoid subprocess overhead
CrewAI Role / crew MIT, CrewAI Inc.; paid enterprise tier The problem decomposes cleanly into specialist roles and you want a multi-agent prototype fast Independent of LangChain. Fast to start, less fine-grained than a graph
Pydantic AI Graph / state-machine MIT, Pydantic Services Inc. You are a type-disciplined Python shop wanting validated structured outputs and durable execution Validation and structured output are first-class. Durable execution preserves progress across restarts
LlamaIndex Data / RAG + agent layer MIT, LlamaIndex Inc.; paid LlamaCloud The hard part is retrieval and document parsing, not orchestration The differentiator is the retrieval stack (see Chapter 86); often paired with another framework for orchestration
Mastra Deterministic TS workflows MIT/Apache (verify per package), Mastra (YC W25) Your team lives in TypeScript and wants a batteries-included stack without crossing into Python Launched early 2026, rapid traction. Workflows are explicit deterministic pipelines
Google ADK Graph / state-machine Apache-2.0, Google; multi-language You are on Google Cloud/Gemini, or want a native graph engine for cyclic and parallel routing Optimized for Gemini but model- and deployment-agnostic
AWS Strands Model-first loop Apache-2.0, AWS You are AWS-centric and want a minimal, model-driven loop without hand-coding orchestration Trades orchestration control for simplicity; leans on the model to drive
Microsoft Agent Framework Graph workflow on SK MIT, Microsoft You are a .NET/Azure enterprise wanting Microsoft's supported, telemetry-rich stack Shipped 1.0 in 2026 as the convergence of Semantic Kernel + AutoGen. Both predecessors are now maintenance-only
AG2 (ex-AutoGen) Conversation-driven multi-agent Apache-2.0, ag2ai/ag2; volunteer You specifically want the AutoGen conversation lineage and human-in-the-loop dialogue patterns The community fork that kept the AutoGen PyPI packages after the creators left Microsoft; innovation has slowed
Figure 85.2. The same frameworks, grouped by loop archetype. Filter by an archetype to see which players fit it, or search by name. What the comparison settles is archetype fit, not a ranking. Versions and licenses as of June 2026.
What's contested

Several 2026 comparison blogs publish ordered "production rankings" of these frameworks (for example LangGraph first, Claude Agent SDK second, CrewAI third). These are individual authors' opinions from small samples, not measured benchmarks, and they are not independently verified. Use them as directional sentiment, never as evidence. The defensible claim is about loop archetype fit, not a leaderboard position.

How to choose, concretely

  • Pick LangGraph when the workflow is a graph: loops, parallel branches, approval gates, long-running, must survive crashes. Accept the boilerplate for the control.
  • Pick the OpenAI Agents SDK when you want the shortest path to a production agent of moderate complexity and value a small, learnable primitive set.
  • Pick the Claude Agent SDK when the agent is Claude working over a filesystem or CLI. Nothing else matches its coding-agent ergonomics.
  • Pick CrewAI when the problem splits cleanly into specialist roles and you want a multi-agent prototype fast.
  • Pick Pydantic AI when you want type safety, validated structured outputs, and durable execution in Python.
  • Pick LlamaIndex when the value is in retrieval and document parsing; use it for the data layer and keep orchestration thin.
  • Pick Mastra when your team is TypeScript-first.
  • Pick Google ADK or AWS Strands when you are committed to that cloud and want the first-party toolkit.
  • Pick Microsoft Agent Framework when you are a .NET/Azure enterprise; it is the supported successor to AutoGen and Semantic Kernel, both now maintenance-only.

A sensible default. For a product team building its first serious agent, follow the loop archetype, not brand loyalty. If the agent is a coding, ops, or filesystem agent, start with the Claude Agent SDK: it hands you a working loop with real tools, context compaction, and MCP, and you extend it with hooks and subagents. For a general task/tool agent of moderate complexity, start with the OpenAI Agents SDK: the primitive set is learnable in an afternoon, it is provider-agnostic, and tracing is built in. Graduate to LangGraph when the workflow outgrows a linear chain and you need loops, parallel branches, approval gates, or durable crash-resume. That migration is a sign of growth, not a failure.

The framework library is not the whole picture. Above it sit two control points the comparison table does not cover: orchestration, the plan that turns an idea into scoped tasks a human can steer, and governance, the record that makes every agent action attributable and every delegated permission able only to narrow. Chapter 75 treats both as first-class layers and works them through the author's own Wallfacer (orchestration) and Topos (governance), disclosed as the author's own and standing there as one illustration of the pattern, not a neutral pick. The practical point is that the framework you choose should leave room for them: a plan artifact a person can review, and a gateway and sandbox whose logs a governance layer can later consume.

Constraint arrow

The framework cannot be more reliable than the gateway and serving layers beneath it (Chapter 82, Chapter 88). This is why "durable execution" and "checkpointing" became the headline 2026 features: they are the framework's attempt to survive failures in the layers below.

MCP: the tool layer underneath everything

MCP is half this story. It is the protocol that lets a tool server, written once, be consumed by every framework above, which is why "what tools does framework X support" became a non-question: the answer is "any MCP server." By 2026 it is the default tool layer underneath almost all of the frameworks in the table.

State of the spec, as of mid-2026:

  • Stable: 2025-11-25. Stateful, with an initialize/initialized handshake plus per-session state. Transports are stdio (local subprocess) and Streamable HTTP (remote service).
  • Release candidate 2026-07-28 (published 21 May 2026), described by the maintainers as the largest revision since launch. The headline is a stateless core: it removes the init handshake and session state, carries protocol metadata in _meta, and adds routing headers (Mcp-Method, Mcp-Name) so load balancers can route without inspecting the body. The point is horizontal scaling on ordinary HTTP infrastructure: any server instance can serve any request. It also formalizes independently versioned extensions (shipping MCP Apps for server-rendered UI and Tasks for async work), a 12-month deprecation policy, and a conformance suite. These are breaking changes versus 2025-11-25. Confirm the final ship date and your client/server support before depending on stateless behavior.
  • Registry and discovery. An official MCP Registry with namespace verification exists, and MCP Server Cards (a .well-known metadata format) let registries and crawlers discover servers without a live connection. The often-cited "500+ public servers" is a moving, secondary-sourced figure.

In production you do not let each agent dial arbitrary MCP servers directly. You route MCP traffic through a governed proxy (an "MCP gateway", agentgateway and similar) that applies auth, allowlists, and audit, the same way a model gateway governs token traffic. The framework speaks MCP either way; whether a tool is a local subprocess, a remote HTTP service, or an in-process function changes almost nothing in the agent code. That portability is the whole point of MCP being a wire protocol rather than a library API.

A minimal sketch of the in-process MCP-tool pattern, in the Claude Agent SDK shape. Check the SDK docs for the exact current API.

from claude_agent_sdk import tool, create_sdk_mcp_server, query, ClaudeAgentOptions

@tool("lookup_order", "Look up an order by id", {"order_id": str})
async def lookup_order(args):
    row = await db.fetch_order(args["order_id"])
    return {"content": [{"type": "text", "text": row.summary()}]}

server = create_sdk_mcp_server(name="ops-tools", version="1.0.0", tools=[lookup_order])

async for msg in query(
    prompt="Refund the late order for customer 4471 and explain why.",
    options=ClaudeAgentOptions(
        mcp_servers={"ops": server},
        allowed_tools=["lookup_order", "Read"],
        # model access resolves through the gateway base_url + virtual key,
        # not a raw provider credential
    ),
):
    print(msg)

The same agent could instead point at an external MCP server over HTTP behind the MCP gateway. The framework code barely changes.

Sandboxes: the execution substrate

A sandbox is a disposable, isolated computer handed to an agent to run untrusted code in. The model writes a Python snippet, a shell command, a git operation, or a whole dev loop, and that code executes somewhere that is not your laptop, not your production cluster, and not sharing a kernel with another tenant's secrets.

The safety argument is blunt: once an agent can execute code, a jailbreak filter on the gateway does nothing against rm -rf, a crypto miner, or an exfiltration curl the model was induced into emitting. The 2026 security consensus (Firecrawl and others) is that the only robust defense is to isolate the physical environment the code runs in, not to ask the model nicely in a system prompt. This is the practical face of Chapter 56: the runtime, not the prompt, is the enforcement boundary.

Two isolation models dominate, and the choice between them is most of the game:

  • MicroVM isolation (Firecracker, Cloud Hypervisor, Kata). Each sandbox is a real, minimal virtual machine with its own guest kernel, separated from the host by hardware virtualization (KVM). This is the strongest commonly-deployed boundary for untrusted code, the same lineage AWS Lambda uses. Firecracker reports booting user code in as little as roughly 125 ms and creating up to roughly 150 microVMs per second per host (project docs, as of 2026).
  • Userspace-kernel / gVisor isolation. A userspace kernel intercepts syscalls so the guest never talks to the host kernel directly. Production-grade (it is what Google Cloud Run uses), trading a sliver of the microVM's hardware separation for faster starts on custom images. Modal uses this model.

A third, weaker tier, plain containers with a shared host kernel, is common but should be treated as a soft boundary for untrusted code unless hardened with gVisor or a microVM underneath. A fourth, V8 isolates (Cloudflare Dynamic Workers), is faster still but only runs sandboxed JS/WASM, not an arbitrary OS. Between a plain container and nothing sits OS-level sandboxing: Anthropic's open-source sandbox-runtime, the containment under Claude Code, confines a process with bubblewrap and seccomp on Linux and sandbox-exec on macOS, with network denied by default behind a proxy. That tier fits a developer's own machine running a semi-trusted agent, not multi-tenant untrusted code.

A comparison of the players

All latency and price claims below are as of mid-2026, vendor-reported or third-party-reported, and not independently verified. Treat the table as a starting map, not a price sheet, and confirm current rates on each vendor's pricing page.

Name Isolation Pricing model (2026) Pick it when Note
E2B Firecracker microVM Open-source SDK; hosted free Hobby + credit, Pro tier, usage per second You want a popular, agent-native, microVM-isolated code box with an open SDK and a self-host path, running short-lived Python/JS tool calls Site claims start "under 200ms"; a circulating "p50 ~78ms" figure is from comparison blogs, not E2B's own page
Modal gVisor (userspace kernel) Hosted; Sandbox CPU billed above the Function rate; optional GPUs The agent must run untrusted code and reach a GPU in the same isolated box (inference, fine-tune steps) Same isolation model as Google Cloud Run; faster custom-image starts, slightly thinner boundary than a full microVM
Fly.io (Machines / Sprites) Firecracker microVM Hosted; per-second CPU+RAM, no charge while idle You want raw microVM control, or snapshot/restore for clean reproducible eval runs with zero idle billing Sprites "start in under a second" (vendor). Sub-10ms restore and "28ms boot" numbers are third-party, treat as unverified
Vercel Sandbox Firecracker microVM Hosted; active-CPU billing, memory billed provisioned for the full run Your app is in the Vercel ecosystem and you run agent-generated code with up to ~45-min lifetimes Bills active CPU but memory is provisioned-billed, watch idle memory cost
Cloudflare Sandbox SDK Container + V8 isolate tier Hosted; active-CPU pricing, requires Workers Paid You are on Cloudflare/Workers and want edge-distributed execution with live preview URLs GA in April 2026. Two tiers: V8 isolates (JS/WASM) and full container sandboxes. Verify cost incl. Durable Objects
Daytona Container base Hosted; usage-based, free credit You want very fast sandbox creation for short-lived agent code runs Claims "sub-90ms" creation, but a container base, so verify the isolation model against your threat model
Runloop Two-layer (VM + container) Hosted; free + usage, Pro tier, enterprise You build a coding agent and want suspend/resume devboxes plus built-in SWE-style benchmarks The differentiator is the eval/benchmark + suspend/resume tooling, not just isolation
Northflank microVM (Kata/gVisor by infra) Self-serve + enterprise; lower headline vCPU/GB rate You want one platform for both app deployment and agent code execution at a lower compute rate Isolation varies by underlying infra; positions on cost + bring-your-own-cloud
Browserbase (+ Anthropic Managed Agents) Isolated headless Chromium Hosted; per-session / per-browser-minute The agent's job is in a browser (web automation, computer-use), not a shell Powers Anthropic's Managed Agents (beta, 2026): Anthropic runs the loop, Browserbase supplies the isolated browser
Firecracker (project) The microVM VMM itself Open source (Apache 2.0), AWS-originated Sandboxing is your core business and you want to operate your own microVM fleet Not a product you use directly; it is the isolation primitive under E2B, Fly, Vercel, Lambda
Cella (latere.ai) Author's own runtime Latere product family; limited public docs The Latere stack, and as a worked example in this book (Chapter 75) Disclosed as the author's own infrastructure; illustrative, not a neutral recommendation. One API call spins up a named ephemeral or persistent sandbox
What's contested

The microVM-versus-gVisor line is a genuine trade-off, not a solved question. MicroVMs (Firecracker) give the strongest hardware boundary but historically cost more in cold start and image-build flexibility; gVisor buys faster custom-image starts at a slightly thinner boundary; plain containers buy speed and density at a real isolation cost. As the gVisor-versus-microVM cost-and-latency curve moves through 2026, the "right" tier for a given threat model moves with it. The one durable claim: for genuinely adversarial, model-generated code, a shared-kernel container is a soft boundary, and hardware or userspace-kernel isolation is the provable line.

How to choose, concretely

The decision is dominated by three axes: isolation strength versus start latency, ephemeral versus persistent, and what the agent needs to touch (shell, GPU, or a browser).

  • Pick E2B when you want the popular, agent-native, microVM-isolated code box with a real open-source SDK and an optional self-host path, running short-lived Python/JS tool calls.
  • Pick Modal when the agent needs to run untrusted code and hit a GPU in the same isolated environment.
  • Pick Fly Machines / Sprites when you want microVM control, snapshot-restore for reproducible eval runs, and zero charge while idle.
  • Pick Vercel or Cloudflare Sandbox when your app already lives in that platform. Weigh Cloudflare's edge distribution and V8 fast path against Vercel's Firecracker boxes and provisioned-memory billing.
  • Pick Runloop when you build a coding agent and want suspend/resume devboxes plus built-in SWE-style benchmarks.
  • Pick Browserbase (or Anthropic Managed Agents) when the agent acts in a browser, not a shell.
  • Self-host on Firecracker only when sandboxing is your core business.

Pricing comparisons are treacherous. "Active CPU only" providers can still bill provisioned memory for the full lifetime (Vercel), and platform minimums or Durable-Object charges (Cloudflare) hide under the headline vCPU rate. Always model your run shape (lifetime, idle fraction, concurrency), not the per-hour sticker.

Change the idle fraction and watch the gap open up between a pure active-CPU bill and one that also charges provisioned memory for the whole lifetime.

# A bursty agent: short CPU spikes between long idle waits on the model.
lifetime_s = 600          # 10-min box, alive the whole task
cpu_price = 0.000040      # $ per active vCPU-second
mem_price = 0.0000060     # $ per provisioned GB-second (billed even while idle)
mem_gb = 2.0
for idle in [0.0, 0.5, 0.8, 0.95]:
    active_s = lifetime_s * (1 - idle)
    cpu_cost = active_s * cpu_price
    mem_cost = lifetime_s * mem_gb * mem_price   # full lifetime, not active only
    total = cpu_cost + mem_cost
    mem_share = 100 * mem_cost / total
    print(f"idle={idle:>4.0%}  active-CPU=${cpu_cost:.4f}  "
          f"provisioned-mem=${mem_cost:.4f}  total=${total:.4f}  "
          f"mem={mem_share:.0f}% of bill")

The takeaway: the higher the idle fraction (the more the agent waits on the model), the more a provisioned-memory line dominates the bill, even on an "active-CPU" provider.

A sensible default. For a team building a code-running agent in 2026, default to E2B for hosted, microVM-isolated execution: agent-native, a real open-source SDK, a self-host escape hatch, strong (Firecracker) isolation, and per-second billing that suits bursty tool calls. If the agent needs a GPU in the box, default to Modal instead. If you specifically want snapshot-restore for reproducible evals (Chapter 87) and zero-idle billing, default to Fly Machines / Sprites. For the Latere stack, the in-house analogue is Cella, disclosed as the author's own infrastructure and therefore not a neutral pick.

Wiring it together safely

The agent framework is a consumer, not a hub. It calls models through the gateway, pulls grounding from retrieval, reaches tools over MCP, runs code in a sandbox, and emits traces the eval and observability layers read. Figure 85.3 shows the shape that holds up in production.

user User / app agent Agent framework loop + memory + handoffs user->agent gw Model gateway agent->gw OpenAI-shaped API virtual key mcpgw MCP gateway agent->mcpgw MCP stdio / HTTP / in-process sb Sandbox microVM / gVisor agent->sb run untrusted code rag Retrieval / vector store agent->rag retrieve ckpt Postgres / SQLite agent->ckpt checkpoint State obs Eval + OTel + cost agent->obs traces human Human approves payments, prod writes agent->human sensitive action? serve Inference serving / hosted APIs gw->serve tools MCP tool servers: db, browser, GitHub, files mcpgw->tools net Internet / approved APIs sb->net default-deny egress + allowlist snap Clean baseline for eval re-runs sb->snap snapshot / restore
Figure 85.3. The production agent runtime. The framework holds no provider key and no raw credentials; model access, tool access, and compute access each reach in through a governed seam.

Three things make this hold up:

  1. The framework never holds a provider key or a raw credential. It holds a gateway virtual key scoped to a model allowlist and a budget, and MCP traffic goes through a gateway that owns tool credentials and the allowlist. Swapping one model for another, or capping a runaway loop, is a server-side change.
  2. State lives in a checkpointer, not in process memory. A durable State (LangGraph's checkpointer, Pydantic AI's durable execution) is what lets a long-running agent survive a restart and lets a human pause, inspect, and resume.
  3. The sandbox keeps secrets, model access, and the network outside the box. They reach in only through narrow, auditable channels: a gateway virtual key for models, short-lived scoped tokens for the credentials a provider will mint and egress substitution for the static secrets it will not (Chapter 56), default-deny egress for the network.

A minimal safe-usage config sketch. The shape matters more than the exact keys; adapt it to your sandbox provider.

sandbox:
  isolation: microvm          # firecracker/gvisor; not a bare container for untrusted code
  lifetime: ephemeral         # destroy after the run: nothing persists, nothing leaks
  timeouts:
    per_tool_call: 30s
    per_task: 10m
    max_lifetime: 30m
  network:
    egress: deny              # default-deny
    allow: ["pypi.org", "api.internal.example.com"]
  secrets:
    inject: none              # no raw provider keys or static secrets in the box
    model_access_via: gateway # short-lived scoped virtual key only
    credentials_via: egress-substitution  # proxy swaps a placeholder for the real secret toward allowed hosts
  audit:
    log: [commands, network_requests, file_writes]   # immutable trail
  approval:
    require_human_for: [payments, production_writes]

The safety practices that recur across 2026 sources, and that close this chapter on the capability, efficiency, trust lens: least-privilege, short-lived credentials; treat every tool or browser output as untrusted input, separating "thinking" from "acting"; default-deny egress with an explicit allowlist; hard timeouts at tool, task, and sandbox-lifetime granularity; immutable audit logs; ephemeral-by-default so state and credentials do not accumulate; and human-in-the-loop gates for irreversible actions.

Further reading

Frameworks and MCP, primary sources:

Sandboxes, primary sources:

Secondary comparisons (used for corroboration only; rankings and opinions in these are not independently verified): QubitTool 2026 framework showdown; TURION.AI LangGraph vs OpenAI vs Claude Agent SDK; WorkOS "Everything your team needs to know about MCP in 2026"; Northflank best sandbox runners (2026).

Comments

Log in to comment