Pydantic AI Harness
Your agent's favorite harness, built on Pydantic AI
Pydantic AI Harness is the official capability and harness library for Pydantic AI. Every Pydantic AI agent already has a light harness: the typed agent loop, any model, your own tools, structured output. For simple agents that's enough. But set an agent loose on complex, long-running work (fix a codebase, research a question, run for hours unattended) and what it needs around the model grows: a workspace to act in, a plan it keeps current, memory that carries across sessions, sub-agents to hand work to, context management that holds up in hour ten, and durable execution that survives a restart. Pydantic AI Harness ships that harness.
Everything here is one primitive: a capability, a self-contained unit of agent behavior you add to capabilities=[...] on any agent. There are 30+ of them, and complete agents like Coder and Researcher are themselves capabilities combined: they come apart the way they went together. Snap on a single block, compose your own stack, or start from the whole coding agent and take it apart later.
Quick start
Install with uv:
uv add "pydantic-ai-harness[anthropic]"
from pydantic_ai import Agent
from pydantic_ai_harness import Coder
agent = Agent('anthropic:claude-fable-5', capabilities=[Coder()])
result = agent.run_sync('Find out why tests/test_parser.py fails and fix the bug it caught.')
print(result.output)
#> Found it: `parse()` returned None on empty input instead of raising. Fixed in src/parser.py; tests pass now.
That's a complete coding agent: workspace-rooted file access, allowlisted shell, repo orientation, planning, a read-only explorer sub-agent, and context management that survives long sessions, and it runs anywhere a Pydantic AI agent runs. agent.to_cli_sync() opens it as a chat in your terminal, agent.to_web() in the browser, and Coder's exported coder_agent runs without writing a file at all, combined with clai (the Pydantic AI CLI) and uvx:
uvx --with pydantic-ai-harness clai -a pydantic_ai_harness.coder:coder_agent -m anthropic:claude-fable-5
Every model works: swap the string for any provider's. Need more? Add capabilities to the list; here's the same coder on gpt-5.6-sol, with web search and cross-session memory:
uv add "pydantic-ai-slim[openai]"
from pydantic_ai import Agent
from pydantic_ai.capabilities import WebSearch
from pydantic_ai_harness import Coder, Memory
from pydantic_ai_harness.memory import FileStore
agent = Agent(
'openai:gpt-5.6-sol',
capabilities=[
Coder(),
WebSearch(), # look up docs and error messages on the web
Memory(FileStore('.agent-memory')), # remembers across sessions
],
)
Skills (your SKILL.md procedures, loaded on demand; point it at a skills/ directory and add the skills extra), Web Fetch, Guardrails, and Dynamic Workflow slot in the same way; the Coder README lists what pairs well.
No magic: it's capabilities all the way down
Coder is not a framework inside the framework; it's a CombinedCapability bundling the same blocks you can use directly. This is the exact agent the exported coder_agent gives you, written out block by block:
from pathlib import Path
from pydantic_ai import Agent
from pydantic_ai_harness import (
ClearToolResults,
FileSystem,
LLM_API_KEY_ENV_PATTERNS,
Planning,
RepoContext,
Shell,
SubAgent,
SubAgents,
ToolOutputLimits,
WarnNearLimits,
)
allowed_commands = [
'git', 'rg', 'grep', 'find', 'ls', 'cat', 'sed', 'head', 'tail',
'python', 'uv', 'pytest', 'ruff', 'make',
]
explorer = SubAgent(
Agent(
name='explorer',
description='Explore the codebase and answer questions without modifying anything',
instructions='Answer with concrete paths and evidence.',
capabilities=[
FileSystem('.', read_only=True),
RepoContext(workspace_dir=Path('.')),
],
)
)
agent = Agent(
'anthropic:claude-fable-5',
name='coder',
instructions='You are a coding agent built on Pydantic AI.',
capabilities=[
FileSystem('.'), # read/write/edit/search, path-traversal safe
Shell( # allowlisted commands, LLM API keys stripped from their environment
cwd='.',
allowed_commands=allowed_commands,
denied_env_patterns=LLM_API_KEY_ENV_PATTERNS,
),
RepoContext(workspace_dir=Path('.')), # loads AGENTS.md/CLAUDE.md + repo structure
Planning(), # structured task plans the model maintains
SubAgents(agents=[explorer], agent_folders=None), # delegate exploration off the main context
ClearToolResults(max_fraction=0.7), # clears old tool results near the limit
WarnNearLimits(max_context_fraction=0.9), # warns the model before it hits limits
ToolOutputLimits(), # bounds oversized tool results
],
)
Start from the harness and remove what you don't want, or start from the blocks and build up; both are first-class. Constructor arguments (working directory, command allowlist, window sizes) thread through to the underlying capabilities.
Capabilities
Every capability is a self-contained unit you drop into capabilities=[...], and they all compose, with each other and with your own. Some come with pydantic-ai itself, the rest with this package; the Package column says which. 50+ in all, grouped by what they give your agent:
Harnesses
Complete agent stacks as regular combined capabilities: one import gives you a working agent, and you can take either apart into the blocks below.
| Harness | Package | What it provides |
|---|---|---|
| Coder | Harness | A complete coding-agent stack: files, shell, repo context, planning, a read-only explorer sub-agent, and context controls |
| Researcher | Harness | A complete web-research stack: search, page fetching, a delegated sub-researcher, and bounded tool output |
Execution environments
The workspace the agent acts in: the files it edits and the commands it runs, local or isolated.
| Capability | Package | What it does |
|---|---|---|
| FileSystem | Harness | Read, write, edit, search files under a root; path-traversal and symlink safe, secrets read-only |
| Shell | Harness | Command execution with allowlists, denylists, timeouts, and credential-stripping |
| Modal Sandbox | Harness | Commands and files in an isolated Modal cloud sandbox |
Tools & native abilities
Connections to systems outside the agent's workspace, and abilities the provider executes natively.
| Capability | Package | What it does |
|---|---|---|
| MCP | Core | Connect any MCP server's tools; local by default, provider-native connectors opt-in |
| Image Generation | Core | Generate and edit images; provider-native where supported, sub-agent fallback elsewhere |
| StackOne | Harness | Act on linked SaaS accounts (HRIS, ATS, CRM, …) via StackOne |
| LocalStack | Harness | An emulated AWS environment with AWS CLI tools |
| Macroscope | Harness | Run a local Macroscope code review and hand the findings to the agent |
Web & research
Finding and reading things on the open web.
| Capability | Package | What it does |
|---|---|---|
| Web Search | Core | Provider-native search where available, local DuckDuckGo fallback everywhere |
| Web Fetch | Core | Fetch and read URLs, native or local |
| X Search | Core | Search X; native on xAI, subagent fallback elsewhere |
| Exa Search | Harness | Web research via Exa: excerpted search, full-page reads, opt-in cited deep search |
| Exa Agent | Harness | Delegate open-ended research to the Exa Agent API |
| Browser Use | Harness | Hand web tasks to an autonomous browser-use agent driving a real browser |
Reasoning, planning & delegation
How the agent thinks and divides the work.
| Capability | Package | What it does |
|---|---|---|
| Thinking | Core | Provider-adaptive extended thinking at configurable effort |
| Planning | Harness | Model-owned task plans with a cache-safe live reminder |
| Subagents | Harness | Delegate self-contained tasks to named child agents |
| Dynamic Workflow | Harness | The model orchestrates sub-agents from one Python script: fan-out, chain, vote in a single tool call, with hard max_agent_calls budgets |
| Advisor | Harness | Let an executor consult a stronger model mid-run |
Context management
How the agent spends its context window: the difference between an agent that degrades over a long run and one that doesn't, and between paying for tokens N times or once.
| Capability | Package | What it does |
|---|---|---|
| Code Mode | Harness | The model writes one Python script that calls many tools inside a Monty sandbox: one round-trip instead of N, and intermediate results never enter the context window. The answer to tool-call token bloat |
| Tool Search | Core | Load tool definitions on demand instead of carrying hundreds in every prompt |
| Compaction | Core | Provider-native compaction on OpenAI and Anthropic; the provider summarizes history server-side |
| Compaction | Harness | Model-agnostic strategies: tool-result clearing, sliding-window trimming, LLM summarization, tiered; all window-relative, with live usage reporting |
| Tool Output Limits | Harness | Truncate, spill to a queryable file, or summarize oversized tool returns at the source |
| Warn On Cache Busts | Harness | Detect prompt-cache prefix collapses between requests, from the provider's own numbers |
Knowledge & memory
What the agent knows and remembers, loaded when relevant instead of carried in every prompt.
| Capability | Package | What it does |
|---|---|---|
| Memory | Harness | A persistent, namespaced notebook: bounded prompt injection, on-demand search; in-memory/file/Postgres stores |
| Conversation Search | Harness | BM25 search over stored history, including turns compaction dropped |
| Skills | Harness | Load Agent Skill (SKILL.md) instructions on demand |
| Repo Context | Harness | Start runs oriented: AGENTS.md/CLAUDE.md + repository structure |
| Pydantic AI Docs | Harness | On-demand Pydantic AI documentation lookup |
Control & safety
Bounding what the agent may do, and keeping it on-instructions.
| Capability | Package | What it does |
|---|---|---|
| Guardrails | Harness | Validate/block/redact user input, tool calls, tool results, and output, including secret masking and parallel async guards |
| Spend Limits | Harness | Cross-window USD/token budgets and per-response cost tracking, per model and per tenant |
| Tool approval | Core | Flag tool calls that need human approval before they run |
| Handle Deferred Tool Calls | Core | Resolve approval-deferred tool calls programmatically |
| System Reminders | Harness | Cache-safe re-injection of guidance mid-run to counter instruction fade |
Self-extension
| Capability | Package | What it does |
|---|---|---|
| Capability Creation | Harness | The agent writes, validates, and persists new capabilities during a run, loaded on the next run: self-extension with typed, inspectable units instead of arbitrary code |
Execution runtime
Outside the loop: how runs persist, survive failures, and get observed and configured in production.
| Capability | Package | What it does |
|---|---|---|
| Durable execution | Core | Runs that survive restarts and failures on Temporal, DBOS, or Prefect, with Restate, Kitaru, and Airflow integrations |
| Step Persistence | Harness | Save, restore, resume (continue_run), and fork (fork_run) runs; file/SQLite/Mongo backends |
| Instrumentation | Core | OpenTelemetry GenAI spans for every model and tool call; the raw material for Logfire traces |
| Managed Prompt | Harness | Back instructions with a Logfire-managed prompt; version and roll out without redeploying |
| Thread Executor | Core | Run sync tools on a shared thread pool |
Core also ships loop-customization capabilities for production servers: Select Model, Resolve Model ID, Prepare Tools / Prepare Output Tools, Prefix Tools, Set Tool Metadata, Include Tool Return Schemas, Process History, Process Event Stream, Reinject System Prompt, and Raise Content Filter Error.
And the agent plugs into any interface: ACP (experimental, Harness) serves it to editors like Zed over the Agent Client Protocol, and core ships the web chat UI, CLI, frontend adapters (AG-UI, Vercel AI), and realtime voice.
Community packages extend the same capability system further; see third-party capabilities.
Composing from blocks
A research agent from regular capabilities -- this is literally Researcher's composition, minus its short default instructions:
from pydantic_ai import Agent
from pydantic_ai.capabilities import WebFetch, WebSearch
from pydantic_ai_harness import SubAgent, SubAgents, ToolOutputLimits
sub_researcher = SubAgent(
Agent(
name='researcher',
description='Research a focused sub-question on the web and report back with findings and source links',
capabilities=[WebSearch(local=True), WebFetch(local=True), ToolOutputLimits()],
)
)
agent = Agent(
'anthropic:claude-fable-5',
capabilities=[
WebSearch(local=True), # native provider search, DuckDuckGo fallback elsewhere
WebFetch(local=True), # read the pages behind the results, native or local
SubAgents(agents=[sub_researcher], agent_folders=None),
ToolOutputLimits(), # fetched pages don't flood the context
],
)
result = agent.run_sync('What changed in the top three Python agent frameworks this month? Cite sources.')
print(result.output)
#> ...
Everything is observable: logfire.instrument_pydantic_ai() gives you a full trace of every run: every model call and tool call, with token and cost tracking. It's standard OpenTelemetry, so any OTLP backend works; Logfire is the easiest way to see it during development.
When do you need the Harness?
"Harness" is the field's term for everything around the model that turns it into an agent: the loop, the tools, the context management. Reach for this package when your agent should do more than core's lean harness covers: touch files, run code, browse, remember, delegate, or stay coherent through hours-long runs. The boundary between the packages is mechanical, not a maturity tier: core ships the capabilities that require model or framework support (provider-native tools like image generation, provider APIs like compaction, deep loop integration like tool search, and fundamentals like thinking, MCP, and web search) and the Harness ships everything else, as a separate package so capabilities can iterate at the speed the field moves while Pydantic AI itself stays lean.
Installation
uv add pydantic-ai-harness
This installs pydantic-ai-slim with it, so it works on its own; you don't need to install Pydantic AI separately. Model providers and the CLI come via extras that pass through to Pydantic AI: pydantic-ai-harness[anthropic], [cli]. Some capabilities need their own extra for optional dependencies; each capability's page gives its exact install line. Requires Python 3.10+.
Build your own
Capabilities are the primary extension point for Pydantic AI, and every capability in this repo doubles as a worked example. Publishing a standalone package? Use the pydantic-ai-<name> naming convention; see Publishing capability packages.
Contributing
We welcome capability contributions:
- Start with an issue. Open a capability request so we can discuss approach and priority before code is written.
- Then open a PR and link the issue. We review based on community interest; upvotes on both count.
- Don't chase green CI. Get the approach working and let us know; we may push to your branch or follow up, and you'll be credited as the original author. (See the Pydantic AI contributing guide.)
Note: PRs that modify
pyproject.tomloruv.lockfrom non-team members are auto-closed by CI to prevent supply chain risk. If you need a new dependency, open an issue.
Development
make install # install dependencies
make format # ruff format
make lint # ruff check
make typecheck # pyright strict
make test # pytest
make testcov # pytest with 100% branch coverage
Version policy
Pydantic AI Harness uses 0.x versioning, and that's a statement about API stability, not maturity: these capabilities are tested end-to-end and meant for production use, but their APIs may still move between minor releases (0.1 -> 0.2): renamed parameters, changed defaults, restructured APIs, always with deprecation warnings where practical. Patch releases will not intentionally break existing behavior, and every breaking change is documented in release notes with migration guidance your agent can follow. Keeping the Harness a separate package from Pydantic AI, which has a stricter version policy, is what lets capabilities iterate at the speed the field moves.
Part of the Pydantic Stack
Everything you need to ship production-grade AI agents:
- Pydantic AI: the type-safe agent framework
- Pydantic Logfire: AI-first, full-stack observability
- Logfire AI Gateway: unified LLM proxy
- Pydantic Evals: evaluate any Python function, agents included
- genai-prices: model pricing data, kept current
License
MIT; see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pydantic_ai_harness-0.21.0.tar.gz.
File metadata
- Download URL: pydantic_ai_harness-0.21.0.tar.gz
- Upload date:
- Size: 2.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5eb429d47977913ccec3e74e48479a6207863efebff9fa9afc4b20e52b01e44a
|
|
| MD5 |
78b06090f3c3719c77a08006e39f6042
|
|
| BLAKE2b-256 |
5791637f34cfb65b9b1a627dc3e4500dff0740c3bd1d369259d40fa11d87e157
|
Provenance
The following attestation bundles were made for pydantic_ai_harness-0.21.0.tar.gz:
Publisher:
main.yml on pydantic/pydantic-ai-harness
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pydantic_ai_harness-0.21.0.tar.gz -
Subject digest:
5eb429d47977913ccec3e74e48479a6207863efebff9fa9afc4b20e52b01e44a - Sigstore transparency entry: 2472355664
- Sigstore integration time:
-
Permalink:
pydantic/pydantic-ai-harness@808f2f6587fb03f5ff84b1a1fc1a3f0cad569757 -
Branch / Tag:
refs/tags/v0.21.0 - Owner: https://github.com/pydantic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
main.yml@808f2f6587fb03f5ff84b1a1fc1a3f0cad569757 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pydantic_ai_harness-0.21.0-py3-none-any.whl.
File metadata
- Download URL: pydantic_ai_harness-0.21.0-py3-none-any.whl
- Upload date:
- Size: 632.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61c1facec51849adc2680569b5abe337e98836ad0e2adc8f79954d01aaa706e6
|
|
| MD5 |
8efdc82b36147239287b66a300ef1c0f
|
|
| BLAKE2b-256 |
6bc1dd669f17415da4d233581cbac8809ea1c2c3078d113289b96103362cdadc
|
Provenance
The following attestation bundles were made for pydantic_ai_harness-0.21.0-py3-none-any.whl:
Publisher:
main.yml on pydantic/pydantic-ai-harness
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pydantic_ai_harness-0.21.0-py3-none-any.whl -
Subject digest:
61c1facec51849adc2680569b5abe337e98836ad0e2adc8f79954d01aaa706e6 - Sigstore transparency entry: 2472355673
- Sigstore integration time:
-
Permalink:
pydantic/pydantic-ai-harness@808f2f6587fb03f5ff84b1a1fc1a3f0cad569757 -
Branch / Tag:
refs/tags/v0.21.0 - Owner: https://github.com/pydantic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
main.yml@808f2f6587fb03f5ff84b1a1fc1a3f0cad569757 -
Trigger Event:
push
-
Statement type: