Skip to main content
Prerequisites. A VisIQ account (sign in) with a harness key from Settings → Harness Keys, Python 3.9+, and a model provider key for Pydantic AI (the sample calls a hosted model — any provider works). Full setup and fixes: Before you start · Troubleshooting.
Add action governance, retrieval governance, and a full audit trail to a Pydantic AI agent by passing it to visiq.govern(). VisIQ registers itself as a Pydantic AI capability, the framework’s own extension point, and wraps the agent’s assembled toolset at its native WrapperToolset.call_tool chokepoint. There are no per-tool wrappers: every tool the agent can call is governed, including @agent.tool tools added later, MCP toolsets and toolsets passed to a single agent.run(..., toolsets=[...]). The visiq wheel, compiled from the same governance core as the TypeScript harness, makes every decision locally, in-process against a cached rule bundle.

Install

Set environment variables

.env
The visiq wheel reads its configuration from the process environment and does not auto-load a project .env. Export the variables (or load them yourself) before calling govern().

Govern your agent

govern() returns the same agent, so it also works as an expression. It is idempotent: governing an agent twice installs governance once. Every tool call is decided before the tool runs. A deny means your function is never called: the block message is returned as the tool’s result, so the model reads why and adjusts course instead of the run crashing. A mask hands your function only the redacted arguments. Tools named in retrieval_tools also have their result governed before it reaches the model, with restricted documents dropped and sensitive fields redacted. A result the retrieval facet cannot split into documents (a dict envelope, a pydantic model) is withheld rather than passed through. Prefer to declare it at construction? The same governance is a capability:
Governance decisions are local and synchronous, but they run off your event loop, so a human-approval hold cannot freeze the rest of your asyncio app. The tool itself still runs in your own task, so cancelling a run also cancels the tool it was running.
On the first run the agent and its tool surface are registered with VisIQ, and each run’s decisions are delivered to the dashboard when that run ends.

Run this on AWS Bedrock

Bedrock is a first-class Pydantic AI model provider, so there is no third-party adapter package — but its boto3 dependency ships in an extra:
Without it the import below raises ImportError: Please install `boto3` to use the Bedrock model — the plain pydantic-ai install at the top of this page is not enough for Bedrock. Then swap the model string for a BedrockConverseModel. The govern() call is unchanged:
Bedrock support needs boto3 available: the full pydantic-ai package already ships it, and on the slim distribution install pydantic-ai-slim[bedrock]. Credentials come from the standard AWS chain (AWS_PROFILE, instance role, AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY). Governance is untouched: the gate fires at the same point, the same rules match, the same rows land in the audit trail. Verified against real Bedrock inference, with no framework-specific caveat. 15 of 15 Bedrock scenario checks passed. Deploying to Bedrock AgentCore Runtime needs nothing extra either — it hosts your process, so install the visiq wheel in your image and set VISIQ_API_KEY in the runtime environment. If instead you use a managed harness, AWS owns the agent loop and this in-process Governor does not apply; see AWS Bedrock for the two chokepoints that still work there.

What happens at runtime

New agents start in monitor mode (observe-only) until you flip them to enforce on the Control Agents → Agents page.
  • Decisions are local. The SDK fetches one cached rule bundle (GET /rules/bundle, ETag revalidation) and refreshes it in the background. Tool calls evaluate in-process; the only decision-path network call is waiting on a human approval.
  • Fail-open by default, loudly — strict deny is opt-in. Real policy outcomes always enforce: an explicit rule deny, the operator kill-switch, and an in-core mask/redact that cannot be applied (it downgrades to deny) all block. A harness-internal failure does NOT block: if the backend is unreachable or the governance core is unavailable, the harness proceeds UNGOVERNED with a loud [VisIQ] FAIL-OPEN (no-bundle) report on stderr, so a VisIQ outage never disrupts your agent (owner decision, 2026-07-15). Set VISIQ_FAIL_MODE=closed to block those harness-internal failures instead.
  • Deny blocks the call. The tool is never executed, and the model receives the block message as the tool result.
  • Approvals pause the call. An approval_required decision holds the tool while a human decides via Slack or Email (Microsoft Teams delivery is built server-side; its connector card is coming soon) — the SDK polls for up to 120 seconds (VISIQ_HITL_TIMEOUT_MS), then fails closed.
  • Mask proceeds, redacted. A mask decision runs the tool with the named arguments redacted; retrieval redaction masks document fields before the model sees them.
Output tools are not governed. The structured final_result a run ends with is the agent’s answer, not an action, so a deny-everything policy still lets the run return. agent.override(root_capability=...) replaces the capability tree for its block, and governance with it. Need finer control than the whole agent? The per-call Governor.gate_tool primitive is documented in the Python SDK Reference.

Verify it’s working

Run the agent once, then open the dashboard:
  • Control Agents → Agents — your agent appears automatically (monitor mode) with a live last-seen heartbeat.
  • Control Agents → Runtime Enforcement — a decision row for every governed tool call, with the matched rule and outcome.

Next steps

Full Quickstart

All supported frameworks and what happens behind the scenes.

Python SDK Reference

The complete Governor API — gate_tool, gate_documents, fail modes.