Repository navigation
Integrations Pydantic AI
Experimental: this works and is tested, but may change and gets less hardening than the stable core.
tracekit.integrations.pydantic_ai.Tracekit is a Pydantic AI capability
that gates every tool call an agent makes, and every output function the model calls through an output tool: its
wrap_tool_execute and wrap_output_process hooks ask the Tracekit signer for a decision before the function runs (an
ask waits for a person) and record the outcome after.
pip install tracekit-ai "pydantic-ai-slim[openai]>=2.57,<2.58"Tested with Pydantic AI 2.57, which needs Python 3.11+. Pick the extra for your model provider ([openai],
[anthropic], ...); the capability itself needs none.
from pydantic_ai import Agent
from tracekit.integrations.pydantic_ai import Tracekit
from tracekit.sdk.client import Client
with Client().run(agent="support-agent") as run:
agent = Agent("openai:gpt-5", tools=[close_account], capabilities=[Tracekit(run)])
agent.run_sync("close ACC-9")Or make import tracekit; tracekit.instrument() the first line: every Agent built after it gets the capability
(an agent given a Tracekit by hand keeps that one alone), and it also records the model calls the agent makes through
the OpenAI, Anthropic and Google Gen AI SDKs (autotrace). An AsyncRunHandle works as well as a RunHandle. Then
tracekit last exports and verifies the run.
Every agent needs the capability, a delegate agent a tool calls included: an agent built before instrument() or
without Tracekit(run) runs its tools ungated. To gate one run of an agent you don't build, pass it to the run:
agent.run(..., capabilities=[Tracekit(run)]). A runnable offline example (a FunctionModel, no API key):
examples/v2/pydantic_ai.
-
Decides the model's own arguments. The signer decides
call.args, the arguments as the model sent them (its JSON text or dict, an empty string as{}); the tool runs with the arguments Pydantic AI validated from them. An approval is bound to those arguments and used once. Under the executor (T2), a call whose approved arguments are not the model's is refused, not run with either. -
Runs outermost. The capability wraps every other one, so a capability that rewrites a call's arguments in
before_tool_executeorwrap_tool_executedoes it inside Tracekit's decision: the call runs, and is recorded asstatus: error, "the call's arguments changed after the decision". -
Never runs a refused call. A deny, a rejected or unanswered approval, a refused consume, a signer refusal, an
outage under a closed fail mode and any error of Tracekit's own all skip the tool (
SkipToolExecution): the model reads Tracekit's reason as the tool's result and the run goes on. Under an open fail mode a call runs unrecorded during an outage, with a warning. -
Records failures as failures. A tool that raises is recorded as
status: errorand its exception reaches Pydantic AI unchanged, soModelRetryand the agent's retries work as before. A retry is a new call id and a new decision. A tool's result goes to the signer as the JSON the model reads (a model or dataclass as its fields, aToolReturnas itsreturn_value), so an untrusted tool's values reach provenance. -
Gates output functions. An output function the model calls through an output tool (
output_type=ToolOutput(fn), or a function inoutput_type) is decided under that tool's name,final_resultby default, and runs only when allowed; a refused one never runs and the model reads the reason as a retry prompt. When streaming, it runs once, on the final output (the partial outputs come back unprocessed). Its call is completed with no result: the model readsFinal result processed., not what the function returned. -
Waits for people. An
askwaits up to 5 minutes (the signer's cap for one wait) before the call; then it is skipped with the approval's state, and an unanswered approval is withdrawn. So is one whose agent run is cancelled while it waits. -
Decides MCP calls once. A tool from an MCP toolset is decided by the capability under its Pydantic AI name; the
ClientSessionthatinstrument()wires doesn't decide it again. -
Keeps Pydantic AI's deferred tools. A tool that raises
ApprovalRequiredorCallDeferredis not completed; when it is resumed withDeferredToolResultsunder the same call id it is decided again as the call's nextattempt. The first attempt then shows asdecided_not_completedonrun.final.
The capability records each model response (after_model_request): its ThinkingParts (a summary, with the
provider's signature) and its text, and each of its calls under the tool_call_id it is decided by, added to the
response only once the capability decides it: a call Pydantic AI never runs (arguments that failed validation, a
data-only output, a tool still waiting for approval) is left out. An approval resumed by another Tracekit capability
(after a restart) adds the call from the history just before its decision (limits).
The message itself is kept only when the signer's content vault is on; without it the record holds a commitment. A message that can't be recorded only warns. Which frameworks and providers return readable reasoning, and how to turn it on: reasoning.
- An
askblocks the tool call while it waits. It does not use Pydantic AI's own deferred tools (ApprovalRequired,DeferredToolRequests): an approval given there is not the signer's and would not be recorded. - Builtin tools the model provider runs (web search, code execution on the provider's side) never reach
wrap_tool_execute; they are seen only in the model responses autotrace records. - Plain structured output (an output type with no function) and text output functions (
TextOutput) are not decided: nothing runs that the model chose. Register a function with side effects as a tool or aToolOutput. Under autotrace the model's output tool calls (final_result,final_result_<Type>per output type) have no tool result: name each in the policy'sstructured_output:, orreconcilereports them. - An argument rewrite in another capability's
before_tool_validateis invisible: it happens before the validated arguments Tracekit compares. - Each signer call, and an
ask's wait, holds a thread of asyncio's default executor; many asks waiting at once can starve it. - The capability holds a live run, so it is not built from an agent spec (
Agent.from_spec). - A call Pydantic AI rejects before
wrap_tool_execute(arguments that fail validation, a tool the agent doesn't have) is never decided. With the LLM gateway it reads as a livereconcile.hook_missing, whose detail says the call ran with no hook gating it, though it never ran: what the model is sent for it is Pydantic AI's retry prompt. - With the gateway's verified tool results, a tool returning a list reaches
Anthropic as one text block per item, which doesn't match the list recorded: such a call reads as
result_mismatch. An output function's call, completed with no result, is not checked.
Generated from docs/ at v1.4.1. Edit the docs in the repository, not here.
Get started
- Quickstart: the v2 signer
- Quickstarts
- Quickstart: Claude Agent SDK
- Quickstart: a custom agent
- Quickstart: LangChain and LangGraph
- Quickstart: MCP client
- Quickstart: OpenAI Agents SDK
- Coding agents other than Claude Code
- tracekit doctor
- Walkthrough: Tracekit end to end
How it works
- How Tracekit works
- Overview
- The life of a tool call
- The evidence format
- Verification and assurance
- Witnesses and monitoring
- Policy
- Approvals
- Detection and containment
- Capture and completeness
- Custody
- Provenance and tracekit why
- Deployment and isolation
- Storage, durability and performance
- Integrations
- Security model
- Architecture
- tracekit why: architecture
Integrations
- Integrations
- Adapters
- OpenTelemetry
- Remote clients
- Kubernetes agent-sandbox
- agentgateway
- agentsh and Tracekit
- Browser Use
- Claude Agent SDK
- Claude Code's sandbox
- Codex's sandbox
- CrewAI
- Docker MCP Gateway
- E2B
- Falco
- Gemini CLI's sandbox
- Google ADK
- Haystack
- LangChain v1
- LiteLLM
- LlamaIndex
- MCP client
- microsandbox
- Microsoft Agent Framework
- OpenAI Agents SDK
- NVIDIA OpenShell
- Pydantic AI
- sandbox-runtime's proxy on its own
- Strands Agents
- Tetragon
- Vercel AI SDK
- Wassette
Policy and approvals
- Policy reference
- Approvals
- Findings
- Reading the model's reasoning
- Incidents and containment
- Webhooks
Deploy and operate
- Deploying the signer
- The signer as a container
- The signer on Kubernetes
- The compose stack
- Identity
- Tool executor
- MCP gateway
- LLM gateway
- Egress observation
- Witnesses
- Log monitor
- Record-key issuer
- Signer observability
- Viewer
- tracekit why: causal investigation and replay
- Migrating
- Platforms
Verify the evidence
- Reading a v2 verify report
- Evidence format v2
- Auditor guide
- Sample evidence bundle
- Signing
- What Tracekit guarantees
Security and privacy
- Threat model: the v2 signer
- Threat model: the v1 laptop signer
- HTTP security checklist
- Threat-model review packet
- Privacy
- Known limits and trade-offs
- What's stable
Compliance
- Compliance mapping
- EU AI Act
- ISO/IEC 42001
- NIST AI RMF and the Generative AI Profile
- OWASP Top 10 lists for LLM and agentic applications
Evaluation
Demos
- Demos
- Agent approvers within bounds
- Completeness and tamper evidence
- Detection and containment
- Network coverage: an egress observer
- Guardrails: allow, deny, or ask a person
- MCP tools, gated and recorded
- Prompt injection held by provenance
- Why: which input caused the action
Help