
Pydantic AI 2.0 wants you to stop building agents like junk drawers
Pydantic AI 2.0 introduces capabilities—reusable bricks of tools, instructions, and hooks. Here's how composing them changes agent building.
Most AI agents in production right now are junk drawers. Open up the codebase and you'll find a single Agent object with a system prompt that's grown to 400 lines, a dozen tools bolted on over six months, some guardrail logic nobody remembers writing, and a handful of hooks that only one engineer understands. It works, mostly. But try to reuse any piece of it in a second agent and you're copy-pasting code, hoping you didn't miss a dependency.
Pydantic AI 2.0 changes that by making the "brick" the unit of agent design instead of the agent itself. It's called a capability, and once you understand it, you stop thinking about agents as monoliths and start thinking about them as assemblies.
What is a capability in Pydantic AI 2.0?
A capability is a self-contained package of everything an agent needs to do one job well. According to the official Pydantic AI v2 announcement, the inner loop of an agent is settled by now: call the model, run a tool, feed the result back. The real leverage is in the layer around it—the hooks that rewrite what the model sees mid-run, context management, steering, and loading the right tools just in time. v2 turns that whole layer into one thing you compose: the capability.
Practically, that means a capability bundles four things that used to live in separate places scattered across your codebase: tools (functions the agent can call), instructions (system prompt fragments), hooks (lifecycle callbacks), and guardrails (validation and safety constraints). Instead of wiring each of those into an Agent() constructor by hand, you define them once as a capability object and hand the whole thing to any agent that needs it.
The GitHub repo for the project puts it plainly: Pydantic AI is extensible by design, letting you build agents from composable capabilities that bundle tools, hooks, instructions, and model settings into reusable units. That single sentence is the whole philosophy shift in a nutshell.
Why does bundling tools and instructions together matter?
Because the old way created invisible coupling. A tool that queries your knowledge base only makes sense alongside the instructions that tell the model when and how to use it. Split those across two different files, and every time you copy the tool into a new agent, you have to remember to copy the instructions too—and update them in two places forever after.
A support-agent example makes this concrete. Imagine a knowledge-base capability that knows how to search your documentation and also carries the instructions for when to cite sources versus when to escalate. Drop that same capability into a simple FAQ widget that never escalates, and it still answers basic questions correctly because the retrieval logic and its instructions travel together. Evolve the knowledge base later—better chunking, a new embedding model—and every agent using that capability improves automatically, with zero rebuilding.
That's the promise laid out by the Pydantic team: capabilities are meant to be dropped into different agents unchanged, because the behavior isn't scattered—it's packaged.
How does progressive disclosure keep agents fast?
One side effect of bundling capabilities is that an agent doesn't need every instruction loaded into its context window at all times. Coverage of the release notes explains this well: Pydantic AI 2.0 also introduces progressive disclosure—by providing a brief description of a capability, an agent can maintain a roster of potential tools to use, loading detailed instructions only when necessary, which helps keep agents lean and cost-effective.
Think of it like a table of contents versus the full book. The agent sees short summaries of what each capability can do, and only pulls in the full instruction set and tool definitions for the capability it actually decides to use on that turn. For agents juggling ten or twenty capabilities, that's the difference between a bloated context window and a snappy one.
What is the Pydantic AI Harness?
You don't have to build every capability from scratch. The Pydantic AI v2 release post introduces a companion library specifically for this: some capabilities ship with Pydantic AI itself; more come from the first-party Pydantic AI Harness, the batteries for your agent (memory, guardrails, context management, file system access, code mode, and more); and others are third-party or your own.
The core framework stays intentionally small. As the announcement puts it, the split is deliberate—core stays small and stable, shipping the loop, the providers, the capability and hooks API, and only the capabilities that need deep provider support or are fundamental to every agent. Everything else—memory systems, sandboxed code execution, human-in-the-loop approval—lives in the Harness or in the growing ecosystem of third-party capability packages, which means you pick what you need instead of inheriting a framework's opinions about everything.
There's also a community angle worth knowing about: plenty already come from the community—VStorm and others ship capabilities that Pydantic AI endorses and links to from the Harness, and is working to upstream. If you're building something common—summarization, sliding-window context management, sandboxed file access—there's a decent chance someone has already published a capability for it rather than you writing one from zero.
How do you actually build a capability?
Here's a bare-bones shape of what defining and composing capabilities looks like, based on the syntax shown in the official announcement:
from pydantic_ai import Agent
from pydantic_ai.capabilities import Capability, Thinking, ToolSearch, WebSearch
knowledge_base_capability = Capability(
name="knowledge_base",
instructions="Search the docs before answering. Cite sources.",
tools=[search_docs],
)
escalation_capability = Capability(
name="escalation",
instructions="If the user is frustrated or the issue is unresolved, escalate.",
tools=[create_support_ticket],
)
support_agent = Agent(
"openai:gpt-5.2",
capabilities=[knowledge_base_capability, escalation_capability],
)
The pattern that matters here isn't the exact syntax—it's that knowledge_base_capability can be lifted out and dropped into a completely different agent (say, a public FAQ widget that never escalates) without modification. Toolsets you've already built aren't wasted either: as the toolsets documentation notes, third-party toolsets can also be wrapped as capabilities, which bundle tools with hooks, instructions, and model settings—see the Extensibility docs for the full ecosystem.
Where do you start if you're new to Pydantic AI?
Start with the Pydantic AI overview docs, which lay out the framework's building blocks in plain language. The docs describe the current toolkit this way: Pydantic AI ships the agent loop, a composable capabilities system, and built-in capabilities for thinking, web search, web fetch, image generation, MCP, tool search, and more; Pydantic AI Harness is the official library of ready-made capabilities—code execution, file access, guardrails, sub-agent orchestration, and more—that you pick and choose from to build coding agents, research assistants, and anything in between.
From there, three resources are worth bookmarking:
- Pydantic AI Agents documentation — covers how agents, tools, and model settings fit together at the code level, including runnable examples with streaming events.
- Toolsets documentation — explains how existing tool collections plug into the capability system, and links out to the broader extensibility ecosystem.
- Multi-Agent Patterns guide — useful once you're composing capabilities across several cooperating agents rather than just one.
- GitHub repository — the source of truth for release notes, issues, and the actual capability implementations you can read for reference.
If you're upgrading from v1, the migration path is less painful than a major version bump usually implies. The release notes are direct about it: coming from v1, upgrade to the latest v1 first and clear every deprecation warning (point a coding agent at them)—that covers most of the migration, and if you do it, almost nothing else should break. There is one behavior change worth flagging manually: openai model names now use the Responses API; use openai-chat: to stay on Chat Completions.
Is this actually different from just organizing your code better?
You could argue capabilities are "just good software engineering"—modularity, separation of concerns, the stuff every senior engineer already tries to do by hand. That's fair. But the difference is that Pydantic AI now enforces and formalizes that structure at the framework level, instead of leaving it as a discipline you have to maintain yourself across a growing codebase. When the framework gives tools, instructions, hooks, and settings a shared container with defined lifecycle points, "good organization" stops being something you hope your team does consistently and becomes something the code itself makes hard to avoid.
That's the real shift worth paying attention to. Not that capabilities let you do something entirely new—but that they make the disciplined way the only convenient way. And in agent development, where context windows get messy fast and technical debt compounds in system prompts nobody wants to touch, convenient discipline is worth more than most new features you'll see this year.