Skip to main content

Govern an AI app I'm building in Python

Surfaces used: Python SDK, framework integrations (LangChain, CrewAI, LangGraph, OpenAI Agents, PydanticAI) Modes supported: Local Hosted Hybrid Tiers: Free (baseline) Solo Teams (hosted features)

What you'll do​

Wrap the dangerous parts of your Python AI app -- tool calls, external API hits, file writes -- with a single guard() check. Policy lives in a YAML file you control; the SDK returns allow/deny with a reason, and logs the decision.

Why this is the right path for you​

  • If you are writing a Python app that invokes LLMs or tools and you own the code, the SDK gives you the finest-grained control.
  • If you use LangChain, CrewAI, LangGraph, OpenAI Agents, or PydanticAI, first-class integration helpers are in Integrations.
  • If you cannot change the code, use the gateway.
  • If your app is Node, use the Node SDK instead.

When NOT to use this approach​

caution

The SDK requires you to call guard() (or use an integration wrapper) at each decision point. If you want a zero-code path that intercepts every LLM request automatically, use the gateway.

5-minute setup​

pip install controlzero

Local mode (no account, policy on disk)​

from controlzero import Client

cz = Client(policy_file="./policy.yaml")

decision = cz.guard(
tool="shell",
args={"command": "rm -rf /"},
)

if not decision.allowed:
raise RuntimeError(f"Blocked by policy: {decision.reason}")

Minimal policy.yaml:

rules:
- id: block-shell-execute
deny: 'shell:execute'
reason: 'Destructive shell commands are not allowed.'
- id: allow-everything-else
allow: '*'
reason: 'Default-allow for everything else.'

Expected output when the rule triggers:

RuntimeError: Blocked by policy: Destructive shell commands are not allowed.

Hosted mode (policy lives in the dashboard)​

import os
from controlzero import Client

cz = Client(api_key=os.environ["CONTROLZERO_API_KEY"])

decision = cz.guard(tool="web_search", args={"query": "..."})

Set CONTROLZERO_API_KEY=cz_live_... in your environment; policy is fetched and kept fresh automatically.

Verifying it's working​

  1. Run your app and watch the audit log (Local mode) or the dashboard Audit page (Hosted).
  2. Trigger a request your policy should deny. Confirm decision.allowed == False and that the event shows up.
  3. Trigger an allowed request. Confirm decision.allowed == True and an allow audit row.

Common follow-ups​

Reference​