Verifiable decision evidence for Pydantic AI agents.
Keep your Pydantic AI models, tools and native approval workflow. LoopGrid records the policy and authority behind consequential actions, enforces tool authorization at execution, and verifies the resulting signed evidence through LoopGrid Core.
pydantic-ai-loopgrid v0.1.0 · validated with Pydantic AI 2.54.0 · Python 3.12 · LoopGrid SDK 0.8.0 · Core 0.8.1-design-partner.
Native execution. Verifiable evidence. Pydantic AI runs the agent and approval lifecycle. LoopGrid connects application-authorized execution to independently verifiable records.
Install the native Pydantic AI capability.
pip install pydantic-ai-loopgrid==0.1.0
Connect the package to your existing LoopGrid Core workspace. It uses pydantic-ai-slim>=2.42,<3 and loopgrid>=0.8.0,<0.9; the validation baseline used Pydantic AI 2.54.0 and Core 0.8.1-design-partner. See the complete package documentation ↗.
Run one consequential sandbox action, then verify it.
This uses Pydantic AI’s local FunctionModel and a simulated refund tool. Start LoopGrid Core on http://127.0.0.1:8000 and substitute a workspace ID already created in Core. No paid model key or real payment system is needed.
import asyncio
from pydantic_ai import Agent, ModelResponse, TextPart, ToolCallPart
from pydantic_ai.models.function import FunctionModel
from pydantic_ai_loopgrid import LoopGridPydanticAI
async def main():
bridge = LoopGridPydanticAI(
base_url="http://127.0.0.1:8000",
workspace_id="YOUR_EXISTING_WORKSPACE_ID",
agent_id="refund-sandbox-agent",
)
decision = bridge.start_decision(
decision_type="sandbox_refund",
agent={"id": "refund-sandbox-agent", "version": "1"},
authority={"acting_for": "local-sandbox", "scope": ["refund:simulate"]},
model={"name": "local-function-model"},
context={"prompt_version": "refund-sandbox-v1"},
proposed_action={"tool": "sandbox_refund", "arguments": {"amount": 25}},
# Supply your application's genuine, versioned policy verdict.
policy={"policy_id": "sandbox-policy", "version": "1", "decision": "auto_allowed"},
)
decision_id = decision["decision_id"]
calls = 0
def scripted_model(messages, info):
nonlocal calls
calls += 1
if calls == 1:
return ModelResponse(parts=[ToolCallPart("sandbox_refund", {"amount": 25})])
return ModelResponse(parts=[TextPart("Sandbox action finished")])
agent = Agent(FunctionModel(scripted_model), capabilities=[bridge.capability(decision_id)])
receipts = []
@agent.tool_plain
def sandbox_refund(amount: int) -> str:
receipt = f"sandbox-receipt-{amount}"
receipts.append(receipt) # local simulated downstream system
return receipt
result = await agent.run("Simulate a refund of 25")
assert receipts == ["sandbox-receipt-25"]
bridge.record_observed_outcome(
decision_id, observer="local-sandbox-ledger", receipt_id=receipts[0],
outcome={"status": "succeeded", "sandbox": True, "real_money_moved": False},
)
record = bridge.get_decision(decision_id)
print(result.output, record["verification"]["valid"])
asyncio.run(main())The policy value in the example represents a verdict supplied by the host application, not an agent-generated authorization. For a workspace-provisioning end-to-end runner with assertions for evidence_complete and cryptographic verification, run native_core_e2e.py ↗.
Capture decisions and the actions that actually run.
start_decision() binds the agent, delegated authority, proposed action and application-provided policy version/verdict.
Native after_model_request captures model_completed evidence with SHA-256 commitments.
wrap_tool_execute checks authorization and actual arguments before dispatch, then records the returned tool result.
record_observed_outcome() records a downstream receipt independently observed by the host application.
LoopGrid Core signs and chains evidence using Ed25519 and SHA-256; export and independent verification use the existing Core tools.
Enforce authority at the actual tool boundary.
Use Pydantic AI’s requires_approval=True deferred-tool flow. The host authenticates the reviewer, records an approval or rejection with record_human_review(), and resumes the agent using DeferredToolResults. LoopGrid independently checks the recorded approval and the exact authorized tool arguments.
Keep authorization durable and recovery explicit.
For local workers sharing one machine and disk, the optional SQLiteAuthorizationStore atomically reserves bounded tool invocations and preserves consumed authorizations across restarts. Tool exceptions remain errors rather than fabricated successful evidence.
from pydantic_ai_loopgrid import LoopGridPydanticAI, SQLiteAuthorizationStore
bridge = LoopGridPydanticAI(
base_url="http://127.0.0.1:8000",
workspace_id="YOUR_EXISTING_WORKSPACE_ID",
authorization_store=SQLiteAuthorizationStore("/local/path/authorizations.db"),
)EvidencePersistenceError preserves a result commitment and flags downstream reconciliation. Do not blindly replay a completed side effect. The SQLite option coordinates workers on the same local disk; multi-host deployments require a shared authorization design.Implementation and recovery guidance: security documentation ↗.
Tested with real Pydantic AI and signed LoopGrid Core.
evidence_complete · 100% applicable evidence coverage · verifyValid: trueExamples use deterministic sandbox tools, not real financial transactions. Signing verifies the integrity and provenance of recorded events; authoritative external receipts remain the application’s responsibility. See the validation record ↗.
Keep Pydantic AI native. Make every consequential decision verifiable.
Connect one real workflow to a signed evidence history, and bring the policy, approval and downstream outcome into the same reviewable trail.