Rename package to pydantic-ai-harness (#207)

- Package name: pydantic-harness -> pydantic-ai-harness
- Python module: pydantic_harness -> pydantic_ai_harness
- Display name: Pydantic Harness -> Pydantic AI Harness
- All URLs updated to github.com/pydantic/pydantic-ai-harness

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Douwe Maan
2026-04-13 14:33:28 -06:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 8cb9941468
commit 987b7312d5
17 changed files with 140 additions and 140 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ body:
- type: input
id: version
attributes:
label: pydantic-harness version
label: pydantic-ai-harness version
placeholder: e.g., 0.1.0
validations:
required: true
@@ -1,5 +1,5 @@
name: Capability Request
description: Propose a new capability for pydantic-harness
description: Propose a new capability for pydantic-ai-harness
labels: ['capability', 'needs:triage']
body:
- type: input
+3 -3
View File
@@ -1,4 +1,4 @@
# Pydantic Harness
# Pydantic AI Harness
## Local setup
@@ -16,7 +16,7 @@ Fill in the absolute path where the `capabilities` branch of `pydantic-ai` is ch
## Vocabulary
- **Capability**: an `AbstractCapability` subclass that bundles tools, hooks, instructions, and model settings into a reusable unit. This is the core abstraction of pydantic-harness
- **Capability**: an `AbstractCapability` subclass that bundles tools, hooks, instructions, and model settings into a reusable unit. This is the core abstraction of pydantic-ai-harness
- **Hook**: a lifecycle method on `AbstractCapability` that intercepts agent graph execution (e.g. `before_model_request`, `wrap_run`, `after_tool_execute`)
- **Toolset**: a collection of tools that a capability can provide to the agent
- **Guard**: a type of capability that validates inputs/outputs or controls tool access (e.g. `InputGuardrail`, `CostGuard`)
@@ -71,7 +71,7 @@ Always run `make lint && make typecheck && make test` before committing.
## File structure
```
pydantic_harness/
pydantic_ai_harness/
__init__.py # public API re-exports
<capability>/ # each capability gets its own package
__init__.py # public exports for the capability
+48 -48
View File
@@ -1,9 +1,9 @@
# Pydantic Harness
# Pydantic AI Harness
[![CI](https://github.com/pydantic/pydantic-harness/actions/workflows/main.yml/badge.svg?event=push)](https://github.com/pydantic/pydantic-harness/actions/workflows/main.yml?query=branch%3Amain)
[![PyPI](https://img.shields.io/pypi/v/pydantic-harness.svg)](https://pypi.python.org/pypi/pydantic-harness)
[![versions](https://img.shields.io/pypi/pyversions/pydantic-harness.svg)](https://github.com/pydantic/pydantic-harness)
[![license](https://img.shields.io/github/license/pydantic/pydantic-harness.svg)](https://github.com/pydantic/pydantic-harness/blob/main/LICENSE)
[![CI](https://github.com/pydantic/pydantic-ai-harness/actions/workflows/main.yml/badge.svg?event=push)](https://github.com/pydantic/pydantic-ai-harness/actions/workflows/main.yml?query=branch%3Amain)
[![PyPI](https://img.shields.io/pypi/v/pydantic-ai-harness.svg)](https://pypi.python.org/pypi/pydantic-ai-harness)
[![versions](https://img.shields.io/pypi/pyversions/pydantic-ai-harness.svg)](https://github.com/pydantic/pydantic-ai-harness)
[![license](https://img.shields.io/github/license/pydantic/pydantic-ai-harness.svg)](https://github.com/pydantic/pydantic-ai-harness/blob/main/LICENSE)
**The batteries for your [Pydantic AI](https://ai.pydantic.dev/) agent.**
@@ -11,7 +11,7 @@
Pydantic AI's [capabilities](https://ai.pydantic.dev/capabilities/) and [hooks](https://ai.pydantic.dev/hooks/) API is how you give an agent its harness -- bundles of tools, lifecycle hooks, instructions, and model settings that extend what the agent can do without any framework changes.
**Pydantic Harness** is the official capability library for Pydantic AI, maintained by the [Pydantic AI](https://github.com/pydantic/pydantic-ai) team. Pydantic AI core ships capabilities that require model or framework support, and capabilities fundamental to every agent -- [web search](https://ai.pydantic.dev/capabilities/#provider-adaptive-tools), [tool search](https://ai.pydantic.dev/deferred-tools/), [thinking](https://ai.pydantic.dev/capabilities/#thinking). Everything else lives here: standalone building blocks you pick and choose to turn your agent into a coding agent, a research assistant, or anything else. This is also where new capabilities start -- as they stabilize and prove themselves broadly essential, they can graduate into core.
**Pydantic AI Harness** is the official capability library for Pydantic AI, maintained by the [Pydantic AI](https://github.com/pydantic/pydantic-ai) team. Pydantic AI core ships capabilities that require model or framework support, and capabilities fundamental to every agent -- [web search](https://ai.pydantic.dev/capabilities/#provider-adaptive-tools), [tool search](https://ai.pydantic.dev/deferred-tools/), [thinking](https://ai.pydantic.dev/capabilities/#thinking). Everything else lives here: standalone building blocks you pick and choose to turn your agent into a coding agent, a research assistant, or anything else. This is also where new capabilities start -- as they stabilize and prove themselves broadly essential, they can graduate into core.
The [capability matrix](#capability-matrix) tracks where we are. [Tell us what to prioritize.](#help-us-prioritize)
@@ -20,13 +20,13 @@ The [capability matrix](#capability-matrix) tracks where we are. [Tell us what t
## Installation
```bash
uv add pydantic-harness
uv add pydantic-ai-harness
```
Extras for specific capabilities:
```bash
uv add "pydantic-harness[code-mode]" # CodeMode (adds the Monty sandbox)
uv add "pydantic-ai-harness[code-mode]" # CodeMode (adds the Monty sandbox)
```
Requires Python 3.10+ and `pydantic-ai-slim>=1.80.0`.
@@ -37,7 +37,7 @@ Requires Python 3.10+ and `pydantic-ai-slim>=1.80.0`.
import logfire
from pydantic_ai import Agent
from pydantic_ai.capabilities import MCP # from the core pydantic-ai package
from pydantic_harness import CodeMode
from pydantic_ai_harness import CodeMode
logfire.configure()
logfire.instrument_pydantic_ai()
@@ -50,56 +50,56 @@ agent = Agent(
],
)
result = agent.run_sync('Rank the open PRs on pydantic/pydantic-harness by thumbs-up reactions. Which 5 should we merge first?')
result = agent.run_sync('Rank the open PRs on pydantic/pydantic-ai-harness by thumbs-up reactions. Which 5 should we merge first?')
print(result.output)
```
[`MCP`](https://ai.pydantic.dev/capabilities/#provider-adaptive-tools) (from the core `pydantic-ai` package) connects your agent to any MCP server -- here, [GitHub's official MCP server](https://github.com/github/github-mcp-server).
[`CodeMode`](pydantic_harness/code_mode/) wraps all tools into a single `run_code` tool powered by our [Monty](https://github.com/pydantic/monty) sandbox, so the model can orchestrate multiple tool calls with Python code instead of one model round-trip per call.
[`CodeMode`](pydantic_ai_harness/code_mode/) wraps all tools into a single `run_code` tool powered by our [Monty](https://github.com/pydantic/monty) sandbox, so the model can orchestrate multiple tool calls with Python code instead of one model round-trip per call.
[`logfire`](https://pydantic.dev/logfire) gives you a trace for every agent run. With CodeMode, you can see the `run_code` span with each nested tool call as a child span -- making it easy to debug what the model's code actually did. See the [Pydantic AI Logfire docs](https://ai.pydantic.dev/logfire/) for setup details.
## Capability matrix
We studied leading coding agents, agent frameworks, and Claw-style assistants to map every capability area that matters for production agents. Each one is tracked as an [issue](https://github.com/pydantic/pydantic-harness/issues) in this repo.
We studied leading coding agents, agent frameworks, and Claw-style assistants to map every capability area that matters for production agents. Each one is tracked as an [issue](https://github.com/pydantic/pydantic-ai-harness/issues) in this repo.
**Vote on whatever is linked in the Status column** -- PRs if we're actively building it, issues if it's planned -- to help us decide what to work on next.
| Category | Capability | Description | Status | Community&nbsp;alternatives |
|---|---|---|---|---|
| **Tools &&nbsp;execution** | **Code mode** | Sandboxed Python execution via [Monty](https://github.com/pydantic/monty) -- one `run_code` call replaces N tool calls | :white_check_mark: [Docs](pydantic_harness/code_mode/) | |
| **Tools &&nbsp;execution** | **Code mode** | Sandboxed Python execution via [Monty](https://github.com/pydantic/monty) -- one `run_code` call replaces N tool calls | :white_check_mark: [Docs](pydantic_ai_harness/code_mode/) | |
| | **Tool search** | Progressive tool discovery for large tool sets | :white_check_mark: [Pydantic&nbsp;AI](https://ai.pydantic.dev/deferred-tools/) | |
| | **File system** | Read, write, edit, search files with path traversal prevention | :construction: [PR&nbsp;#177](https://github.com/pydantic/pydantic-harness/pull/177) | [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend) (vstorm&#8209;co) |
| | **Shell** | Execute commands with allowlists, denylists, and timeouts | :construction: [PR&nbsp;#177](https://github.com/pydantic/pydantic-harness/pull/177) | [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend) (vstorm&#8209;co) |
| | **Repo context injection** | Auto-load CLAUDE.md/AGENTS.md and repo structure | :construction: [PR&nbsp;#175](https://github.com/pydantic/pydantic-harness/pull/175) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| | **Verification loop** | Run tests after edits, auto-fix failures | :construction: [PR&nbsp;#169](https://github.com/pydantic/pydantic-harness/pull/169) | |
| **Context management** | **Sliding window** | Trim conversation history to stay within token limits | :construction: [PR&nbsp;#191](https://github.com/pydantic/pydantic-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm&#8209;co) |
| | **Context compaction** | LLM-powered summarization of older messages | :construction: [PR&nbsp;#191](https://github.com/pydantic/pydantic-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm&#8209;co) |
| | **Limit warnings** | Warn agent before hitting context/iteration limits | :construction: [PR&nbsp;#191](https://github.com/pydantic/pydantic-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm&#8209;co) |
| | **Tool output management** | Truncate, summarize, or spill large tool outputs | :construction: [PR&nbsp;#185](https://github.com/pydantic/pydantic-harness/pull/185) | |
| | **System reminders** | Inject periodic reminders to counteract instruction drift | :construction: [PR&nbsp;#181](https://github.com/pydantic/pydantic-harness/pull/181) | |
| **Memory &&nbsp;persistence** | **Memory** | Persistent key-value memory across sessions | :construction: [PR&nbsp;#179](https://github.com/pydantic/pydantic-harness/pull/179) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| | **Session persistence** | Save and restore full conversation state | :construction: [PR&nbsp;#176](https://github.com/pydantic/pydantic-harness/pull/176) | |
| | **Checkpointing** | Save, rewind, and fork conversation state | :memo: [#196](https://github.com/pydantic/pydantic-harness/issues/196) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| **Agent orchestration** | **Sub-agents** | Delegate subtasks to specialized child agents | :construction: [PR&nbsp;#178](https://github.com/pydantic/pydantic-harness/pull/178) | [subagents-pydantic-ai](https://github.com/vstorm-co/subagents-pydantic-ai) (vstorm&#8209;co) |
| | **Skills** | Progressive tool loading -- search, activate, deactivate | :construction: [PR&nbsp;#183](https://github.com/pydantic/pydantic-harness/pull/183) | [pydantic-ai-skills](https://github.com/DougTrajano/pydantic-ai-skills) (DougTrajano), [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| | **Planning** | Break complex tasks into structured plans before execution | :construction: [PR&nbsp;#180](https://github.com/pydantic/pydantic-harness/pull/180) | |
| | **Task tracking** | Track tasks, subtasks, and dependencies | :memo: [#65](https://github.com/pydantic/pydantic-harness/issues/65) | [pydantic-ai-todo](https://github.com/vstorm-co/pydantic-ai-todo) (vstorm&#8209;co) |
| | **Teams** | Multi-agent teams with shared state and message bus | :memo: [#195](https://github.com/pydantic/pydantic-harness/issues/195) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| **Safety &&nbsp;guardrails** | **Input guardrails** | Validate user input before the agent run starts | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Output guardrails** | Validate model output after the run completes | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Cost/token budgets** | Enforce token and cost limits per run | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Tool access control** | Block tools or require approval before execution | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Async guardrails** | Run validation concurrently with model requests | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Secret masking** | Detect and redact secrets in agent I/O | :construction: [PR&nbsp;#172](https://github.com/pydantic/pydantic-harness/pull/172) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Approval workflows** | Require human approval for sensitive operations | :construction: [PR&nbsp;#173](https://github.com/pydantic/pydantic-harness/pull/173) | [Pydantic&nbsp;AI](https://ai.pydantic.dev/deferred-tools/#human-in-the-loop-tool-approval) (built&#8209;in) |
| | **Tool budget** | Limit total tool calls or cost per run | :construction: [PR&nbsp;#168](https://github.com/pydantic/pydantic-harness/pull/168) | |
| **Reliability** | **Stuck loop detection** | Detect and break out of repetitive agent loops | :construction: [PR&nbsp;#186](https://github.com/pydantic/pydantic-harness/pull/186) | |
| | **Tool error recovery** | Retry failed tool calls with backoff and budget | :construction: [PR&nbsp;#171](https://github.com/pydantic/pydantic-harness/pull/171) | |
| | **Tool orphan repair** | Fix orphaned tool calls in conversation history | :construction: [PR&nbsp;#184](https://github.com/pydantic/pydantic-harness/pull/184) | |
| **Reasoning** | **Adaptive reasoning** | Adjust thinking effort based on task complexity | :construction: [PR&nbsp;#174](https://github.com/pydantic/pydantic-harness/pull/174) | |
| | **Current time** | Inject current date/time into system prompt | :construction: [PR&nbsp;#170](https://github.com/pydantic/pydantic-harness/pull/170) | |
| | **File system** | Read, write, edit, search files with path traversal prevention | :construction: [PR&nbsp;#177](https://github.com/pydantic/pydantic-ai-harness/pull/177) | [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend) (vstorm&#8209;co) |
| | **Shell** | Execute commands with allowlists, denylists, and timeouts | :construction: [PR&nbsp;#177](https://github.com/pydantic/pydantic-ai-harness/pull/177) | [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend) (vstorm&#8209;co) |
| | **Repo context injection** | Auto-load CLAUDE.md/AGENTS.md and repo structure | :construction: [PR&nbsp;#175](https://github.com/pydantic/pydantic-ai-harness/pull/175) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| | **Verification loop** | Run tests after edits, auto-fix failures | :construction: [PR&nbsp;#169](https://github.com/pydantic/pydantic-ai-harness/pull/169) | |
| **Context management** | **Sliding window** | Trim conversation history to stay within token limits | :construction: [PR&nbsp;#191](https://github.com/pydantic/pydantic-ai-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm&#8209;co) |
| | **Context compaction** | LLM-powered summarization of older messages | :construction: [PR&nbsp;#191](https://github.com/pydantic/pydantic-ai-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm&#8209;co) |
| | **Limit warnings** | Warn agent before hitting context/iteration limits | :construction: [PR&nbsp;#191](https://github.com/pydantic/pydantic-ai-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm&#8209;co) |
| | **Tool output management** | Truncate, summarize, or spill large tool outputs | :construction: [PR&nbsp;#185](https://github.com/pydantic/pydantic-ai-harness/pull/185) | |
| | **System reminders** | Inject periodic reminders to counteract instruction drift | :construction: [PR&nbsp;#181](https://github.com/pydantic/pydantic-ai-harness/pull/181) | |
| **Memory &&nbsp;persistence** | **Memory** | Persistent key-value memory across sessions | :construction: [PR&nbsp;#179](https://github.com/pydantic/pydantic-ai-harness/pull/179) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| | **Session persistence** | Save and restore full conversation state | :construction: [PR&nbsp;#176](https://github.com/pydantic/pydantic-ai-harness/pull/176) | |
| | **Checkpointing** | Save, rewind, and fork conversation state | :memo: [#196](https://github.com/pydantic/pydantic-ai-harness/issues/196) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| **Agent orchestration** | **Sub-agents** | Delegate subtasks to specialized child agents | :construction: [PR&nbsp;#178](https://github.com/pydantic/pydantic-ai-harness/pull/178) | [subagents-pydantic-ai](https://github.com/vstorm-co/subagents-pydantic-ai) (vstorm&#8209;co) |
| | **Skills** | Progressive tool loading -- search, activate, deactivate | :construction: [PR&nbsp;#183](https://github.com/pydantic/pydantic-ai-harness/pull/183) | [pydantic-ai-skills](https://github.com/DougTrajano/pydantic-ai-skills) (DougTrajano), [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| | **Planning** | Break complex tasks into structured plans before execution | :construction: [PR&nbsp;#180](https://github.com/pydantic/pydantic-ai-harness/pull/180) | |
| | **Task tracking** | Track tasks, subtasks, and dependencies | :memo: [#65](https://github.com/pydantic/pydantic-ai-harness/issues/65) | [pydantic-ai-todo](https://github.com/vstorm-co/pydantic-ai-todo) (vstorm&#8209;co) |
| | **Teams** | Multi-agent teams with shared state and message bus | :memo: [#195](https://github.com/pydantic/pydantic-ai-harness/issues/195) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm&#8209;co) |
| **Safety &&nbsp;guardrails** | **Input guardrails** | Validate user input before the agent run starts | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Output guardrails** | Validate model output after the run completes | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Cost/token budgets** | Enforce token and cost limits per run | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Tool access control** | Block tools or require approval before execution | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Async guardrails** | Run validation concurrently with model requests | :construction: [PR&nbsp;#182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Secret masking** | Detect and redact secrets in agent I/O | :construction: [PR&nbsp;#172](https://github.com/pydantic/pydantic-ai-harness/pull/172) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm&#8209;co) |
| | **Approval workflows** | Require human approval for sensitive operations | :construction: [PR&nbsp;#173](https://github.com/pydantic/pydantic-ai-harness/pull/173) | [Pydantic&nbsp;AI](https://ai.pydantic.dev/deferred-tools/#human-in-the-loop-tool-approval) (built&#8209;in) |
| | **Tool budget** | Limit total tool calls or cost per run | :construction: [PR&nbsp;#168](https://github.com/pydantic/pydantic-ai-harness/pull/168) | |
| **Reliability** | **Stuck loop detection** | Detect and break out of repetitive agent loops | :construction: [PR&nbsp;#186](https://github.com/pydantic/pydantic-ai-harness/pull/186) | |
| | **Tool error recovery** | Retry failed tool calls with backoff and budget | :construction: [PR&nbsp;#171](https://github.com/pydantic/pydantic-ai-harness/pull/171) | |
| | **Tool orphan repair** | Fix orphaned tool calls in conversation history | :construction: [PR&nbsp;#184](https://github.com/pydantic/pydantic-ai-harness/pull/184) | |
| **Reasoning** | **Adaptive reasoning** | Adjust thinking effort based on task complexity | :construction: [PR&nbsp;#174](https://github.com/pydantic/pydantic-ai-harness/pull/174) | |
| | **Current time** | Inject current date/time into system prompt | :construction: [PR&nbsp;#170](https://github.com/pydantic/pydantic-ai-harness/pull/170) | |
> Packages by [vstorm-co](https://github.com/vstorm-co) are endorsed by the Pydantic AI team. We're working with them to upstream some of their implementations into this repo.
@@ -107,7 +107,7 @@ We studied leading coding agents, agent frameworks, and Claw-style assistants to
**Vote on whatever is linked in the Status column above.** If there's a PR, vote on the PR -- it means we're actively building it. If there's only an issue, vote on the issue.
Want something that's not on the list? [Open a capability request](https://github.com/pydantic/pydantic-harness/issues/new?template=capability-request.yml).
Want something that's not on the list? [Open a capability request](https://github.com/pydantic/pydantic-ai-harness/issues/new?template=capability-request.yml).
## Build your own
@@ -119,11 +119,11 @@ Want something that's not on the list? [Open a capability request](https://githu
We welcome capability contributions. Here's how:
1. **Start with an issue.** [Open a capability request](https://github.com/pydantic/pydantic-harness/issues/new?template=capability-request.yml) describing the behavior you want. This lets us discuss the approach and priority before code is written -- we can close an approach without closing the problem.
1. **Start with an issue.** [Open a capability request](https://github.com/pydantic/pydantic-ai-harness/issues/new?template=capability-request.yml) describing the behavior you want. This lets us discuss the approach and priority before code is written -- we can close an approach without closing the problem.
2. **Then open a PR.** Once the issue exists, you're welcome to open a PR with an implementation. Link the issue in your PR. We review based on community interest -- upvotes on both the issue and PR count.
3. **Don't chase green CI.** Get the approach working, then let us know. We'll take it from there -- we may push to your branch, rewrite, or open a follow-up PR. You'll be credited as the original author. (See the [Pydantic AI contributing guide](https://github.com/pydantic/pydantic-ai/blob/main/CONTRIBUTING.md).)
> **Note**: PRs that modify `pyproject.toml` or `uv.lock` from non-team members are auto-closed by CI to prevent supply chain risk. If you need a new dependency, [open an issue](https://github.com/pydantic/pydantic-harness/issues/new).
> **Note**: PRs that modify `pyproject.toml` or `uv.lock` from non-team members are auto-closed by CI to prevent supply chain risk. If you need a new dependency, [open an issue](https://github.com/pydantic/pydantic-ai-harness/issues/new).
### Development
@@ -138,14 +138,14 @@ make testcov # pytest with 100% branch coverage
## Version policy
Pydantic Harness uses **0.x versioning** to signal that APIs are still stabilizing. During 0.x:
Pydantic AI Harness uses **0.x versioning** to signal that APIs are still stabilizing. During 0.x:
- **Minor releases** (0.1 → 0.2) may include breaking changes — renamed parameters, changed defaults, restructured APIs. As the library grows, especially as capabilities gain provider-native support (starting as a local implementation, then auto-switching to the provider's built-in API when available), we may need to reshape APIs we couldn't fully anticipate in the initial design.
- **Patch releases** (0.1.0 → 0.1.1) will not intentionally break existing behavior.
- **All breaking changes** are documented in release notes with migration guidance.
- Where practical, we'll keep the previous behavior available under a deprecated name or configuration option before removing it.
This is why Pydantic Harness is a separate package from [Pydantic AI](https://github.com/pydantic/pydantic-ai), which has a [stricter version policy](https://ai.pydantic.dev/version-policy/). As the core capabilities stabilize, we'll move toward 1.0 with stability guarantees to match.
This is why Pydantic AI Harness is a separate package from [Pydantic AI](https://github.com/pydantic/pydantic-ai), which has a [stricter version policy](https://ai.pydantic.dev/version-policy/). As the core capabilities stabilize, we'll move toward 1.0 with stability guarantees to match.
## Pydantic AI references
@@ -1,4 +1,4 @@
"""Agent harness for composable, reusable AI agent capabilities, for Pydantic AI."""
"""The batteries for your Pydantic AI agent -- the official capability library."""
from typing import TYPE_CHECKING
@@ -21,7 +21,7 @@ Standard tool calling requires one model round-trip per tool call. An agent that
```python
from pydantic_ai import Agent
from pydantic_harness import CodeMode
from pydantic_ai_harness import CodeMode
agent = Agent('anthropic:claude-sonnet-4-6', capabilities=[CodeMode()])
@@ -56,7 +56,7 @@ tokyo_c = await convert_temp(fahrenheit=tokyo['temp_f'])
Code mode requires the Monty sandbox:
```bash
uv add "pydantic-harness[code-mode]"
uv add "pydantic-ai-harness[code-mode]"
```
## Selective tool sandboxing
@@ -81,7 +81,7 @@ Tools that match the selector are wrapped inside `run_code`. Non-matching tools
```python
from pydantic_ai import Agent
from pydantic_ai.toolsets import FunctionToolset
from pydantic_harness import CodeMode
from pydantic_ai_harness import CodeMode
search_tools = FunctionToolset(tools=[search, fetch]).with_metadata(code_mode=True)
@@ -149,7 +149,7 @@ capabilities:
```python
from pydantic_ai import Agent
from pydantic_harness import CodeMode
from pydantic_ai_harness import CodeMode
agent = Agent.from_file('agent.yaml', custom_capability_types=[CodeMode])
result = agent.run_sync('...')
@@ -0,0 +1,6 @@
"""Code mode capability: route tool calls through a sandboxed Python environment."""
from pydantic_ai_harness.code_mode._capability import CodeMode
from pydantic_ai_harness.code_mode._toolset import CodeModeToolset
__all__ = ['CodeMode', 'CodeModeToolset']
@@ -9,7 +9,7 @@ from pydantic_ai.capabilities import AbstractCapability, CapabilityOrdering
from pydantic_ai.capabilities._tool_search import ToolSearch as _ToolSearch
from pydantic_ai.tools import AgentDepsT, ToolSelector
from pydantic_harness.code_mode._toolset import CodeModeToolset
from pydantic_ai_harness.code_mode._toolset import CodeModeToolset
@dataclass
@@ -26,7 +26,7 @@ class CodeMode(AbstractCapability[AgentDepsT]):
```python
from pydantic_ai import Agent
from pydantic_harness import CodeMode
from pydantic_ai_harness import CodeMode
# Sandbox all tools
agent = Agent('openai:gpt-5', capabilities=[CodeMode()])
@@ -41,7 +41,7 @@ try:
)
except ImportError as _import_error: # pragma: no cover
raise ImportError(
'pydantic-monty is required for CodeMode. Install it with: pip install "pydantic-harness[code-mode]"'
'pydantic-monty is required for CodeMode. Install it with: pip install "pydantic-ai-harness[code-mode]"'
) from _import_error
from typing_extensions import NotRequired, TypedDict
-6
View File
@@ -1,6 +0,0 @@
"""Code mode capability: route tool calls through a sandboxed Python environment."""
from pydantic_harness.code_mode._capability import CodeMode
from pydantic_harness.code_mode._toolset import CodeModeToolset
__all__ = ['CodeMode', 'CodeModeToolset']
+8 -8
View File
@@ -3,7 +3,7 @@ requires = ['hatchling', 'uv-dynamic-versioning>=0.7.0']
build-backend = 'hatchling.build'
[project]
name = 'pydantic-harness'
name = 'pydantic-ai-harness'
dynamic = ['version']
description = 'The batteries for your Pydantic AI agent'
readme = 'README.md'
@@ -43,13 +43,13 @@ dbos = [
]
[project.urls]
Homepage = 'https://github.com/pydantic/pydantic-harness'
Source = 'https://github.com/pydantic/pydantic-harness'
Issues = 'https://github.com/pydantic/pydantic-harness/issues'
Homepage = 'https://github.com/pydantic/pydantic-ai-harness'
Source = 'https://github.com/pydantic/pydantic-ai-harness'
Issues = 'https://github.com/pydantic/pydantic-ai-harness/issues'
[dependency-groups]
dev = [
'pydantic-harness[code-mode]',
'pydantic-ai-harness[code-mode]',
'pytest',
'anyio[trio]',
'pytest-anyio',
@@ -74,7 +74,7 @@ bump = true
[tool.hatch.build.targets.wheel]
packages = ['pydantic_harness']
packages = ['pydantic_ai_harness']
[tool.ruff]
line-length = 120
@@ -119,10 +119,10 @@ anyio_mode = 'auto'
[tool.coverage.run]
branch = true
source = ['pydantic_harness', 'tests']
source = ['pydantic_ai_harness', 'tests']
[tool.coverage.paths]
source = ['.', '/home/runner/work/pydantic-harness/pydantic-harness']
source = ['.', '/home/runner/work/pydantic-ai-harness/pydantic-ai-harness']
[tool.coverage.report]
fail_under = 100
+3 -3
View File
@@ -26,9 +26,9 @@ from pydantic_ai.usage import RunUsage
from pydantic_core import SchemaValidator, core_schema
from typing_extensions import TypedDict
from pydantic_harness import CodeMode
from pydantic_harness.code_mode import CodeModeToolset
from pydantic_harness.code_mode._toolset import ( # pyright: ignore[reportPrivateUsage]
from pydantic_ai_harness import CodeMode
from pydantic_ai_harness.code_mode import CodeModeToolset
from pydantic_ai_harness.code_mode._toolset import ( # pyright: ignore[reportPrivateUsage]
_SEARCH_TOOLS_MODIFIER,
_TOOL_SEARCH_ADDENDUM,
_PrintCapture,
+2 -2
View File
@@ -25,7 +25,7 @@ from pydantic_ai.messages import ModelRequest, ModelResponse, TextPart, ToolCall
from pydantic_ai.models.function import AgentInfo, FunctionModel
from pydantic_ai.toolsets.function import FunctionToolset
from pydantic_harness import CodeMode
from pydantic_ai_harness import CodeMode
# ---------------------------------------------------------------------------
# Fixtures
@@ -36,7 +36,7 @@ from pydantic_harness import CodeMode
def dbos_instance(tmp_path_factory: pytest.TempPathFactory) -> Generator[DBOS, Any, None]:
dbos_sqlite_file = tmp_path_factory.mktemp('dbos') / 'dbostest.sqlite'
dbos_config: DBOSConfig = {
'name': 'pydantic_harness_dbos_tests',
'name': 'pydantic_ai_harness_dbos_tests',
'system_database_url': f'sqlite:///{dbos_sqlite_file}',
'run_admin_server': False,
'enable_otlp': False,
+2 -2
View File
@@ -38,12 +38,12 @@ from pydantic_ai.messages import ModelRequest, ModelResponse, TextPart, ToolCall
from pydantic_ai.models.function import AgentInfo, FunctionModel
from pydantic_ai.toolsets.function import FunctionToolset
from pydantic_harness import CodeMode
from pydantic_ai_harness import CodeMode
pytestmark = pytest.mark.anyio
TEMPORAL_PORT = 7244 # avoid conflict with other test suites
TASK_QUEUE = 'pydantic-harness-code-mode-queue'
TASK_QUEUE = 'pydantic-ai-harness-code-mode-queue'
BASE_ACTIVITY_CONFIG = ActivityConfig(
start_to_close_timeout=timedelta(seconds=60),
retry_policy=RetryPolicy(maximum_attempts=1),
+3 -3
View File
@@ -3,12 +3,12 @@ from pathlib import Path
from pydantic_ai import Agent
from pydantic_ai.models.test import TestModel
import pydantic_harness
import pydantic_ai_harness
def test_import():
assert pydantic_harness.__doc__ is not None
assert isinstance(pydantic_harness.__all__, list)
assert pydantic_ai_harness.__doc__ is not None
assert isinstance(pydantic_ai_harness.__all__, list)
def test_test_model_fixture(test_model: TestModel):
Generated
+55 -55
View File
@@ -863,6 +863,61 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" },
]
[[package]]
name = "pydantic-ai-harness"
source = { editable = "." }
dependencies = [
{ name = "pydantic-ai-slim" },
]
[package.optional-dependencies]
code-mode = [
{ name = "pydantic-monty" },
]
dbos = [
{ name = "pydantic-ai-slim", extra = ["dbos"] },
]
temporal = [
{ name = "pydantic-ai-slim", extra = ["temporal"] },
]
[package.dev-dependencies]
dev = [
{ name = "anyio", extra = ["trio"] },
{ name = "coverage" },
{ name = "logfire", extra = ["httpx"] },
{ name = "pydantic-ai-harness", extra = ["code-mode"] },
{ name = "pytest" },
{ name = "pytest-anyio" },
]
lint = [
{ name = "pyright" },
{ name = "ruff" },
]
[package.metadata]
requires-dist = [
{ name = "pydantic-ai-slim", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" },
{ name = "pydantic-ai-slim", extras = ["dbos"], marker = "extra == 'dbos'", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" },
{ name = "pydantic-ai-slim", extras = ["temporal"], marker = "extra == 'temporal'", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" },
{ name = "pydantic-monty", marker = "extra == 'code-mode'", specifier = ">=0.0.10" },
]
provides-extras = ["code-mode", "dbos", "temporal"]
[package.metadata.requires-dev]
dev = [
{ name = "anyio", extras = ["trio"] },
{ name = "coverage" },
{ name = "logfire", extras = ["httpx"], specifier = ">=4.31.0" },
{ name = "pydantic-ai-harness", extras = ["code-mode"] },
{ name = "pytest" },
{ name = "pytest-anyio" },
]
lint = [
{ name = "pyright", specifier = ">=1.1.408" },
{ name = "ruff", specifier = ">=0.14" },
]
[[package]]
name = "pydantic-ai-slim"
version = "1.80.0"
@@ -1015,61 +1070,6 @@ dependencies = [
{ name = "typing-inspection" },
]
[[package]]
name = "pydantic-harness"
source = { editable = "." }
dependencies = [
{ name = "pydantic-ai-slim" },
]
[package.optional-dependencies]
code-mode = [
{ name = "pydantic-monty" },
]
dbos = [
{ name = "pydantic-ai-slim", extra = ["dbos"] },
]
temporal = [
{ name = "pydantic-ai-slim", extra = ["temporal"] },
]
[package.dev-dependencies]
dev = [
{ name = "anyio", extra = ["trio"] },
{ name = "coverage" },
{ name = "logfire", extra = ["httpx"] },
{ name = "pydantic-harness", extra = ["code-mode"] },
{ name = "pytest" },
{ name = "pytest-anyio" },
]
lint = [
{ name = "pyright" },
{ name = "ruff" },
]
[package.metadata]
requires-dist = [
{ name = "pydantic-ai-slim", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" },
{ name = "pydantic-ai-slim", extras = ["dbos"], marker = "extra == 'dbos'", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" },
{ name = "pydantic-ai-slim", extras = ["temporal"], marker = "extra == 'temporal'", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" },
{ name = "pydantic-monty", marker = "extra == 'code-mode'", specifier = ">=0.0.10" },
]
provides-extras = ["code-mode", "dbos", "temporal"]
[package.metadata.requires-dev]
dev = [
{ name = "anyio", extras = ["trio"] },
{ name = "coverage" },
{ name = "logfire", extras = ["httpx"], specifier = ">=4.31.0" },
{ name = "pydantic-harness", extras = ["code-mode"] },
{ name = "pytest" },
{ name = "pytest-anyio" },
]
lint = [
{ name = "pyright", specifier = ">=1.1.408" },
{ name = "ruff", specifier = ">=0.14" },
]
[[package]]
name = "pydantic-monty"
version = "0.0.11"