Skip to main content

acp-pydantic-ai

Agentic Control Plane governance for Pydantic AI agents.

Register ACPHooks() once on your agent. Before any tool runs, ACP decides allow / deny / redact based on your workspace's policy, the end user's scopes, rate limits, and PII detection — for every tool the agent has, with zero per-function decorators.

Same governance model as Claude Code. If you have workspace policies set up for Claude Code, they apply to Pydantic AI tools automatically.

Install

pip install acp-pydantic-ai

Requires pydantic-ai >= 2 (the package builds on Pydantic AI's first-class Hooks capability).

Usage

from fastapi import FastAPI, Header
from pydantic_ai import Agent
from acp_pydantic_ai import ACPHooks, configure, set_context

configure(base_url="https://api.agenticcontrolplane.com")
app = FastAPI()

# One registration. Every tool on this agent is governed — the ones
# below, and any you add later.
agent = Agent(
    "anthropic:claude-sonnet-4-6",
    instructions="You are an ACP-governed agent. Use the tools available.",
    capabilities=[ACPHooks()],
)

@agent.tool_plain
def lookup_record(id: str) -> str:
    """Look up a record by ID."""
    return db.lookup(id)            # your code, your credentials

@agent.tool_plain
def send_email(to: str, subject: str, body: str) -> str:
    """Send an email on behalf of the user."""
    return sendmail(to, subject, body)

@app.post("/run")
def run(prompt: str, authorization: str = Header(...)):
    # Bind the end user's JWT to this request's context. Every tool call
    # in the run below carries the user's identity to ACP.
    set_context(user_token=authorization.removeprefix("Bearer ").strip())
    return {"result": agent.run_sync(prompt).output}

What happens per tool call

  1. Pre-check — POSTs to ACP /govern/tool-use with { tool_name, tool_input, session_id } + the user's Bearer JWT.
  2. Decide — ACP evaluates workspace policy, the user's scopes, rate limits, and PII.
  3. Deny → the tool function is never called. The model receives "tool_error: <reason>" as the tool result and adapts.
  4. Allow → your tool runs.
  5. Post-audit — POSTs to /govern/tool-output with the result. PII scan runs. redact → the redacted version replaces the output; block → the model sees "[ACP] Blocked: <reason>".

How it hooks in

ACPHooks() returns a Pydantic AI Hooks capability carrying a single tool_execute wrap hook (wrap_tool_execute). Pydantic AI invokes it around every tool execution; the hook runs the pre-check, calls await handler(args) only on allow, then runs the post-audit. It composes with your other capabilities and hooks — first-registered wraps outermost.

Scope it if you need to:

ACPHooks(tools=["send_email", "delete_record"])   # govern only these
ACPHooks(exclude=["get_time"])                    # govern all but these

Decorator pattern (v1-era, still works)

Before Pydantic AI 2, this package's story was stacking @governed under the tool decorator:

from acp_pydantic_ai import governed

@agent.tool_plain
@governed("lookup_record")
def lookup_record(id: str) -> str: ...

That still works on v2 and is still re-exported here. Prefer ACPHooks() — one registration, nothing to forget on the next tool. Don't combine both on the same tool, or the call is checked (and audited) twice.

View activity

Every tool call shows up in the ACP Activity view, rooted in the end user's identity. Sessions group related calls — one request from one user = one session.

Fail-open

Network errors, timeouts (5s default), gateway errors → the tool proceeds with reason "fail-open". Matches Claude Code behavior. Governance is never a single point of failure for the agent.

API

acp-pydantic-ai re-exports the full acp-governance API for convenience:

ACPHooks(tools=None, exclude=None)        # → pydantic_ai.capabilities.Hooks
governed(name_or_fn=None)                 # v1-era decorator, still supported
set_context(user_token, *, session_id=None, agent_tier=None, agent_name=None)
get_context()
clear_context()
configure(base_url=..., timeout_s=..., client_header=...)

License

MIT

Metadata

Release files for acp-pydantic-ai 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for acp-pydantic-ai 0.2.0
File Size Uploaded Provenance Actions
acp_pydantic_ai-0.2.0.tar.gz 5.0 kB Without provenance Details for acp_pydantic_ai-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for acp-pydantic-ai 0.2.0
File Interpreter ABI Platform Actions
acp_pydantic_ai-0.2.0-py3-none-any.whl Python 3 none any Details for acp_pydantic_ai-0.2.0-py3-none-any.whl

Total release size: 11.2 kB

Release files / acp_pydantic_ai-0.2.0.tar.gz

Download URL acp_pydantic_ai-0.2.0.tar.gz
Size 5.0 kB
Tags Source
SHA-256 checksum
How to use checksums
be7fee9b184eac9f37f2fdfd7f2f106e2a4945e86b861f5dd12d34fe0f5ef0fe
BLAKE2b-256 checksum
How to use checksums
0502ee2df577c051af906e71347f28bd71c9099553ef75f831602a3ae83c2cbc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Release files / acp_pydantic_ai-0.2.0-py3-none-any.whl

Download URL acp_pydantic_ai-0.2.0-py3-none-any.whl
Size 6.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
19913e42d5db6ef862a8687901982ad2d95a87a3db3335f7f8a6238a5fb2a5cd
BLAKE2b-256 checksum
How to use checksums
daffb477abc650460ffd2ba06611deda30ed3b5270e7bc3e0670252de577ed8b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Security for acp-pydantic-ai 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page