All Governor’s Log Release / Pydantic AI

Sentience Governor for Pydantic AI

Execution evidence at the point where agent actions actually happen. Also: while we were building it, our own coding agent showed us why it matters.

Sentience Governor for Pydantic AI is live.

pip install pydantic-ai-governor
from pydantic_ai import Agent
from pydantic_ai_governor import SentienceGovernor

agent = Agent("openai:gpt-4o", capabilities=[SentienceGovernor()])

From that point, every run of that agent carries governance evidence: what the run was asked to do, and what it actually executed.

Sentience Governor records what an AI agent did at the execution boundary and compares it against what the agent said it was going to do. It has governed Claude Code, MCP clients and LangChain for a while. Pydantic AI is the newest runtime, and it is the one we were most interested in reaching.

Why Pydantic AI

We want governance evidence to be available across agentic runtimes, and the runtimes are not equally easy to record faithfully. Pydantic AI gives us an unusually precise execution boundary.

Its tool-execution hooks run around validated tool calls at the point they are actually being dispatched. A call that fails validation never reaches the hook. That means we are not inferring what happened from a broader callback or a transport boundary and hoping the inference holds. We are recording the action where the action occurs.

That precision is what let the integration be specific rather than approximate. It also set the standard the rest of the work had to meet.

The design decisions behind the adapter

A framework this precise about its own execution semantics deserves a record that follows those semantics rather than one that forces the framework into our abstraction. Four decisions came out of that, and each is as much about what we chose not to do.

Use Pydantic AI’s lifecycle instead of inventing one. A Pydantic AI run is the governance session. The run’s own run_id is the session id, so the two systems agree on identity with no mapping table between them to drift apart.

We took that choice with its cost. A resumed deferred execution is a new Pydantic AI run, so it becomes a new Governor session rather than being silently stitched to the previous one.

Match evidence by identity, not by position. A scope assertion is written immediately before a tool is dispatched, and a snapshot after it returns. The obvious way to pair them is “the next snapshot after this assertion,” and that is wrong: a single model response can issue several tool calls at once, and retries and deferred approval reorder things further. Both records carry the framework’s own tool_use_id, so a pair is matched by identity. Position is not evidence once anything runs concurrently.

Record only what was actually asserted. A run’s objective and scope come from what the developer declared, not from the prompt. A tool’s operation and target come from what the developer classified, not from the tool’s name. A tool called db_delete_record is not recorded as a delete against a database.

A missing declaration therefore stays missing in the record. A derived objective would look better and mean less, because a reviewer could no longer tell what the agent was actually told.

Stay observational in 0.1.0. Producing a faithful record is its own problem, and it has to be solved before anything can be built on top of it. Acting on what the record shows is a separate design problem, and this release does not attempt it.

Several things were left out deliberately rather than overlooked: cost figures, reasoning-token accounting, correlation across runs, object-level scope inside a target system, and any claim about whether a call succeeded beyond what the record can show. Each needs semantics we do not yet have, and inventing them would have put confident-looking fields into an evidence record on the strength of a guess.

One subtlety worth showing

Per-turn usage comes from the model response itself. During the spike we found that the running usage total at that lifecycle point lags by one request, so relying on it would misattribute turns and omit the final one. The tests lock that behavior down.

What a run records

For each run, one session, keyed to Pydantic AI’s own run_id:

  • The declaration, before anything executes: the objective and scope you gave the run, or an honest record that none was given.
  • A scope assertion after validation and immediately before each tool is dispatched.
  • A snapshot after each tool returns normally.
  • Per-turn token usage, model and provider identity, read from the model response itself.
  • An unclassified call is still recorded, honestly marked as unclassified, because a call nobody classified is a fact about the session worth having.

The capability observes and records. It does not intervene. Nothing is halted, refused, delayed or altered. Across the execution paths we tested for this release, attaching the capability did not change agent output, message count, token usage, exception propagation, retries, deferral, streaming or control flow.

And then we ran into the problem ourselves

While building the integration, our own coding agent reported four consecutive checkpoints as validated. The reports were detailed and specific. They were also accurate about everything they described.

Meanwhile a continuous-integration job had been failing since the first time it ran. It was the job we had added precisely to catch problems across the Python versions the package claims to support, and it was red on the oldest one from the moment it existed.

The local test evidence in those reports was real. It had all been produced on a single Python version. Nothing in the reports said so, and nothing in them was false.

The evidence existed the entire time. We simply had not looked at it.

The problem was not that the evidence did not exist. It was that a plausible agent report was easier to consume than the underlying execution record.

What that changes

An agent that summarizes its own work may be right and can still sound complete when the evidence is incomplete. That is precisely why the summary is not the evidence.

Governance is not only about catching malicious or spectacular agent behavior. Sometimes it is about having an independent record for the ordinary case: when an agent tells you, confidently and in detail, that the work is done.

pydantic-ai-governor writes that record for Pydantic AI runs. It is append-only, it stays on your machine by default, and it is readable by the same analyzers as any other Sentience Governor session. It requires no Sentience account and no Sentience API key.

Availability

pydantic-ai-governor 0.1.0 is on PyPI under Apache-2.0, and it is an independent distribution: it depends on sentience-governor, and Sentience Governor takes on no Pydantic AI dependency in return. The two version and release separately.

It supports Python 3.10 through 3.13 against pydantic-ai-slim 2.37.

Full documentation is in the package README, including what the evidence does and does not prove. We have also opened a pull request to add the integration to Pydantic AI’s third-party capability documentation.