VORIM
We use cookies

We use cookies to analyze site traffic and improve your experience. You can choose to accept all cookies or only essential ones. See our Privacy Policy.

Pydantic AIPythonIntegrationDeveloper Tools

Type-Safe Agent Identity for Pydantic AI: Permissions and Audit Trails the Pydantic Way

S
Kwame Nyantakyi
April 15, 2026 · 6 min read

Your Agents Have Type Safety. Do They Have Identity?

Pydantic AI is one of the fastest-growing AI agent frameworks in 2026, and for good reason. It brings Python's type system to agent development: structured outputs, dependency injection, model-agnostic design, and the kind of validation that catches bugs before they hit production.

But type safety solves one problem. Agent identity solves a different one.

When your Pydantic AI agent calls a tool, who is it? What is it allowed to do? Is there a record of what it did? If something goes wrong at 3am, can you trace which agent, with which permissions, took which action?

Today we're releasing vorim.pydantic_ai, a type-safe integration that adds cryptographic identity, scoped permissions, and tamper-proof audit trails to Pydantic AI agents through dependency injection.

The Pattern: VorimDeps

Pydantic AI's dependency injection lets you pass typed context to your agents and tools via RunContext. Vorim plugs directly into this pattern.

from vorim.pydantic_ai import VorimDeps
from pydantic_ai import Agent, RunContext

agent = Agent('openai:gpt-4o', deps_type=VorimDeps)

@agent.tool
async def fetch_data(ctx: RunContext[VorimDeps], query: str) -> str:
    # Check permission before acting
    check = ctx.deps.check('data:read')
    if not check.get('allowed'):
        return 'Permission denied: data:read not granted'

    result = await do_something(query)

    # Log the action
    ctx.deps.emit('data.fetch', outcome='success')
    return result

# Run with Vorim identity
deps = VorimDeps(api_key='agid_sk_...', agent_id='agid_abc123')
result = await agent.run('Fetch the latest data', deps=deps)
VorimDeps is a dataclass with four key methods:
  • check(scope) — verify the agent has a permission before acting (sub-5ms via Redis)
  • emit(action, outcome) — log an audit event with SHA-256 hash linking
  • grant(scope) — grant a permission to the agent
  • verify() — check the agent's trust score (0-100)

The Vorim client is lazy-initialized, so creating VorimDeps is instant. The API connection only happens when you call a method.

The vorim_tool Decorator

Manually calling check() and emit() in every tool works, but it's boilerplate. The vorim_tool decorator handles it automatically:

from vorim.pydantic_ai import VorimDeps, vorim_tool

agent = Agent('openai:gpt-4o', deps_type=VorimDeps)

@agent.tool
@vorim_tool(scope='data:read', action='data.fetch')
async def fetch_data(ctx: RunContext[VorimDeps], query: str) -> str:
    # Permission is checked before this runs
    # Audit event is emitted after this returns
    return await do_something(query)

What happens under the hood: 1. Before your tool runs: checks if the agent has the required scope. If denied, returns a configurable deny message and logs a denial event. 2. After your tool runs: emits an audit event with the action name and outcome (success or error). 3. If the tool throws: catches the exception, logs an error event, then re-raises.

Every tool call becomes an identifiable, auditable, permission-checked action. Zero additional code in the tool itself.

Why This Matters for Production

In development, agents run in a sandbox with your credentials. Nobody cares about permissions. In production, agents run autonomously across systems with access to real data, real APIs, and real money.

The questions that come up:
  • "Which agent modified that customer record?" — Without per-agent identity, you can't tell. With VorimDeps, every action is tied to a specific agent ID with a cryptographic keypair.
  • "Was the agent allowed to do that?" — Without scoped permissions, agents inherit whatever access the host application has. With vorim_tool(scope='data:write'), the agent is blocked if it doesn't have the right scope.
  • "Prove to the auditor that the agent acted within its bounds." — Without tamper-proof logs, you have "we think this happened." With Vorim's SHA-256 hash chain, you have cryptographic proof that the log hasn't been altered.

One-Call Agent Creation

If you want to skip the manual setup, create_vorim_agent registers a new agent with Vorim and returns a pre-configured Pydantic AI Agent with VorimDeps:

from vorim.pydantic_ai import create_vorim_agent

agent, deps = create_vorim_agent(
    model='openai:gpt-4o',
    api_key='agid_sk_...',
    agent_name='research-agent',
    scopes=['data:read', 'agent:execute'],
    system_prompt='You are a research agent.',
)

# Agent is registered with Vorim, permissions granted, ready to go
result = await agent.run('Find the latest papers on agent security', deps=deps)

Behind the scenes: registers the agent (Ed25519 keypair generated), grants the requested scopes, and wires up the dependency type. The deps object already has the agent ID set.

Sync and Async

The vorim_tool decorator works with both synchronous and asynchronous tools. Pydantic AI supports both, and so does the Vorim integration:

# Async tool
@agent.tool
@vorim_tool(scope='data:read', action='data.fetch')
async def fetch_data(ctx: RunContext[VorimDeps], query: str) -> str:
    return await async_fetch(query)

# Sync tool — works the same way
@agent.tool
@vorim_tool(scope='data:read', action='data.lookup')
def lookup_data(ctx: RunContext[VorimDeps], key: str) -> str:
    return sync_lookup(key)

Testing with VorimDeps

Pydantic AI's agent.override(deps=...) pattern works naturally with VorimDeps. In tests, you can override with a mock or a test instance:

# Test with a real Vorim test environment
test_deps = VorimDeps(
    api_key='agid_sk_test_...',
    agent_id='agid_test_agent',
    base_url='https://vorim.ai/v1',  # or your test instance
)

with agent.override(deps=test_deps):
    result = await agent.run('Test query')
    assert 'expected' in result.data

The Broader Picture

This integration is part of Vorim's growing ecosystem:
  • LangChain, OpenAI, Claude, CrewAI, LlamaIndex — framework integrations for TypeScript and Python
  • Google A2A Protocol — identity and trust for agent-to-agent communication
  • MCP Server — 17 tools for Claude and MCP-compatible clients
  • CLI Toolnpx @vorim/cli init for terminal-first developers
  • IETF Internet-Draft — standardizing agent identity across the industry

Pydantic AI is the seventh framework integration and the most type-safe one yet. If you care about code quality enough to use Pydantic AI, you probably care about security enough to want identity and audit trails.

Get Started

pip install vorim pydantic-ai

Full documentation: vorim.ai/docs (Pydantic AI section) PyPI: pypi.org/project/vorim/ GitHub: github.com/Vorim-AI-Labs/vorim-ai

If you're building with Pydantic AI and thinking about agent security, reach out at team@vorim.ai or book a call at vorim.ai/contact.

Ready to build with agent identity?

Free plan: 3 agents, 10K auth events/month, full SDK access. No credit card.