* docs: add stale-PR re-eval, experimental-export, and consumer-lens guidance Adopting a months-old PR (#243) surfaced three gaps in the AICA review/authoring guides: - no discipline for re-evaluating a stale or pre-merge PR (retire temporary uv.sources pins once upstream lands; re-check drift vs current main) - the experimental-vs-top-level export convention was undocumented, so the code_mode exemplar steered new-capability authors toward top-level exports - the review checklist named "dogfooding need" but no reference consumer or the cache/cost/reliability lens a long-running background coder cares about Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: key export-stability rule on shipped-in-release, not on a symbol list Only CodeMode has shipped in a published release (v0.3.0 exports just CodeMode); FileSystem, ManagedPrompt, and Shell are top-level on main but pre-release. The earlier wording labeled all four "already-released", which is inaccurate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: drop the reference-consumer lens bullet Keep the two clearest gaps (stale-PR re-eval, experimental-vs-released exports); drop the consumer-lens addition, which named pydanty (a separate repo) in the harness review checklist and was the most likely to read as out-of-place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: David SF <david.sanchez@pydantic.dev> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.3 KiB
Pydantic AI Harness
Repository purpose
pydantic-ai-harness is the first-party capability library for Pydantic AI.
Pydantic AI core owns the primitive runtime: agent loop semantics, normalized messages, model/provider/profile behavior, tool execution semantics, durable execution primitives, and generic capability hooks.
Harness owns optional, batteries-included compositions built from those primitives: coding-agent tools, guardrails, memory, context management, repo tools, verification loops, skills, planning, sub-agents, and other reusable agent behaviors.
When a change needs new core semantics, stop and propose the Pydantic AI core change instead of reimplementing core behavior in harness.
Vocabulary
- Capability: an
AbstractCapabilitysubclass 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
AbstractCapabilitythat 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) - Harness: this package -- a collection of pre-made capabilities for Pydantic AI.
- AICA: AI Code Assistant -- the automated agent that implements issues, reviews plans, and handles PR feedback
- Ralph loop: the state-machine-based workflow that drives AICA through phases (TRIAGE -> GOALS -> PLAN -> CODE -> VERIFY -> REVIEW -> PUBLISH)
- DDD+ protocol: classification system for PR review comments (do, dismiss, discuss, waiting, done)
AICA preflight
Before implementing or reviewing a capability change:
- Read
agent_docs/index.md. - Read the linked
agent_docs/guide for the task. - Read the public Pydantic AI docs for every integration point you touch:
- capabilities: https://pydantic.dev/docs/ai/core-concepts/capabilities/
- hooks: https://pydantic.dev/docs/ai/core-concepts/hooks/
- toolsets: https://pydantic.dev/docs/ai/tools-toolsets/toolsets/
- advanced tools: https://pydantic.dev/docs/ai/tools-toolsets/tools-advanced/
- agents: https://pydantic.dev/docs/ai/core-concepts/agent/
- testing: https://pydantic.dev/docs/ai/guides/testing/
- Inspect the installed
pydantic_aipackage source for exact hook/toolset signatures when needed. Do not assume a contributor's local checkout layout. - Use
pydantic_ai_harness.code_modeas the exemplar for capability shape, docs, tests, and public exports until another capability becomes a better example.code_modeis a released top-level capability; new capabilities start underpydantic_ai_harness.experimental(seeagent_docs/capability-authoring.md, "Experimental Vs Released Exports").
Capabilities API reference
When implementing a new capability, reference these docs:
- https://pydantic.dev/docs/ai/core-concepts/capabilities/ -- main capabilities documentation, usage patterns, built-in capabilities
- https://pydantic.dev/docs/ai/core-concepts/hooks/ -- lifecycle hooks reference, hook ordering, all hook categories
- https://pydantic.dev/docs/ai/guides/extensibility/ -- publishing capabilities as packages, spec serialization
- https://pydantic.dev/docs/ai/tools-toolsets/toolsets/ -- toolset abstraction, building tools for capabilities
- https://pydantic.dev/docs/ai/tools-toolsets/tools-advanced/ -- tool hooks, prepare tools, tool validation
- https://pydantic.dev/docs/ai/core-concepts/agent/ -- agent configuration, instructions, model settings
- Installed
pydantic_ai.capabilitiessource --AbstractCapability, hook signatures, and composition behavior - Installed
pydantic_ai.toolsetssource --AbstractToolset,WrapperToolset, andToolsetTool
Coding standards
- Python 3.10+ (target version for pyright and ruff)
- pyright strict mode -- no
Anytypes, full type annotations - ruff: line-length=120, single quotes, max-complexity=15
- 100% branch coverage required (enforced by
make testcov) - docstrings use single backticks (markdown), not RST double backticks
- no typecasting (
asin TypeScript,cast()in Python) -- use type narrowing instead - prefer the most generic input types possible (reduce dependency chains)
- don't add comments that restate what the code does
Writing style
Applies to docs, READMEs, docstrings, comments, commit messages, and PR text.
- No em-dashes (
—). Use--for an aside or interruption, or split into two sentences. Em-dash-heavy prose reads as machine-generated. - State facts, not sales copy. Cut marketing superlatives and hype ("blazingly fast", "battle-tested", "the single most expensive thing you can do", "footgun") and editorializing adjectives ("sprawling", "noisy", "silently").
- Avoid absolute claims ("never", "always", "guaranteed") unless they are literally true and load-bearing. Name the specific mechanism instead of the slogan.
- Use bold sparingly -- for the lead-in term of a list item, not to emphasize whole sentences.
- Document the why, the constraints, and the non-obvious. Don't restate what the code or signature already says.
- Prefer plain ASCII punctuation over decorative Unicode (arrows, fancy quotes) in prose and comments.
Package management
- Use
uvfor all dependency operations - Never edit
pyproject.tomloruv.lockdirectly -- useuv add,uv remove - External PRs that change dependencies are auto-closed by CI
Commands
make format # ruff format
make lint # ruff check
make typecheck # pyright strict
make test # pytest
make testcov # pytest with branch coverage
Always run make lint && make typecheck && make test before committing.
File structure
pydantic_ai_harness/
__init__.py # public API re-exports
<capability>/ # each capability gets its own package
__init__.py # public exports for the capability
_capability.py # capability class (AbstractCapability subclass)
_toolset.py # toolset implementation
README.md # standalone docs for the capability
tests/
conftest.py # shared fixtures (TestModel, test_agent)
<capability>/ # tests mirror source packages
test_<capability>.py
Do not add placeholder template files for new capabilities. Start from the
existing CodeMode package shape, then delete what the new capability does not
need.
Testing patterns
- Use
pydantic_ai.models.TestModelfor all tests (no real API calls) ALLOW_MODEL_REQUESTS = Falseis set globally inconftest.py- Tests use
pytest-anyiofor async support - Each capability test class follows:
TestCapabilityNamewith methodstest_<scenario> - Prefer tests through
Agent(..., capabilities=[...])when that is the public behavior. Use directToolset/RunContexttests for lower-level lifecycle, schema, retry, or wrapper behavior that is hard to isolate throughAgent.
Contributing rules for AICAs
- Never change
pyproject.tomloruv.lock-- if a dependency is needed, open an issue - Always link sources for any claims made during research
- Run
make lint && make typecheck && make testbefore every commit - Commit messages should summarize the "why", not the "what"
- All GitHub comments must start with "Claude here: "