Skip to main content

AI agent governance: policies, audit, and observability for tool calls. Works locally with no signup.

Project description

control-zero

AI agent governance for Python. Policies, audit, and observability for tool calls. Works locally with no signup.

v1.0.0 is a complete rewrite. If you depend on control-zero<1.0.0 (the hosted-mode SDK), pin your requirement: control-zero<1.0.0 to stay on the legacy v0.3.x. The new v1.0.0+ is a local-first SDK with a different API surface; see the migration guide for details.

Hello World

from controlzero import Client

cz = Client(policy={
    "rules": [
        {"deny":  "delete_*", "reason": "Hello World: deletes are blocked"},
        {"allow": "*",        "reason": "Hello World: everything else is fine"},
    ]
})

print(cz.guard("delete_file", {"path": "/tmp/foo"}).decision)  # "deny"
print(cz.guard("read_file",   {"path": "/tmp/foo"}).decision)  # "allow"

11 lines. No API key. No signup. Run it.

Install

pip install control-zero

Why

Your AI agents call tools. Some of those tools should never be called by an agent without a human in the loop. controlzero is the policy layer between the model's output and the tool execution. Decisions are fail-closed by default.

You can use it offline with a local YAML file or Python dict. When you want to share policies across a team or get a hosted audit dashboard, sign up at controlzero.ai and set CONTROLZERO_API_KEY.

Quickstart with the CLI

# 1. Generate a starter policy file with examples and comments
controlzero init

# 2. Edit controlzero.yaml in your editor

# 3. Validate it
controlzero validate

# 4. Test a tool call against the policy
controlzero test delete_file

The generated controlzero.yaml is the tutorial. It ships with annotated rules covering the common patterns: allow lists, deny lists, wildcards, and the catch-all.

Templates available:

  • controlzero init — Hello World template (default)
  • controlzero init -t rag — RAG agent template (block exfiltration)
  • controlzero init -t mcp — MCP server template
  • controlzero init -t cost-cap — model allow-listing and cost guards

Loading a policy

Three ways:

from controlzero import Client

# From a Python dict
cz = Client(policy={
    "rules": [
        {"deny": "delete_*"},
        {"allow": "read_*"},
    ]
})

# From a YAML file
cz = Client(policy_file="./controlzero.yaml")

# From an environment variable
# (set CONTROLZERO_POLICY_FILE=./controlzero.yaml)
cz = Client()

If ./controlzero.yaml exists in the current directory, it is picked up automatically. No environment variable needed.

Policy schema

version: '1'
rules:
  # Block any tool whose name starts with "delete_"
  - deny: 'delete_*'
    reason: 'Deletes need human approval'

  # Allow specific known-good tools
  - allow: 'search'
  - allow: 'read_*'

  # tool:method syntax
  - allow: 'github:list_*'
  - deny: 'github:delete_repo'

  # Catch-all
  - deny: '*'
    reason: 'Default deny'

Rules are evaluated top to bottom. The first match wins. If no rule matches, the call is denied (fail-closed).

Tamper detection and quarantine

The policy YAML supports a settings: section that controls how the SDK responds when it detects that the local policy file has been modified outside of normal channels (manual edits, unexpected hash changes, etc.):

version: '1'
settings:
  tamper_behavior: warn # Options: warn | deny | deny-all | quarantine
rules:
  - deny: 'delete_*'
  - allow: '*'
Mode Behavior
warn Log a warning but continue evaluating rules normally.
deny Deny the current tool call that triggered the tamper check.
deny-all Deny all tool calls and place the machine in quarantine until recovered.
quarantine Same as deny-all, plus report a tamper alert to the backend dashboard.

Quarantine recovery. When a machine enters quarantine (deny-all or quarantine), every tool call is denied until you re-establish trust with one of these commands:

controlzero enroll
controlzero policy-pull
controlzero sign-policy

Org-level policy signing. When a machine is enrolled via controlzero enroll, it receives the organization's signing public key. Policy bundles pulled from the backend are cryptographically signed and verified by the SDK automatically. No extra configuration is required.

Tamper alert reporting. In quarantine mode, the SDK reports a tamper alert to the Control Zero backend so your team can see it on the dashboard.

Local audit log

When running without an API key, every decision is written to ./controlzero.log with daily rotation and 30-day retention. Tail it:

controlzero tail

Configure rotation via the client:

cz = Client(
    policy_file="./controlzero.yaml",
    log_path="./logs/controlzero.log",
    log_rotation="10 MB",        # rotate at 10 MB, or "daily", or "1 hour"
    log_retention="30 days",
    log_compression="gz",        # gzip rotated files
    log_format="json",           # or "pretty"
)

When CONTROLZERO_API_KEY is set, audit ships to the remote dashboard and these log_* options are ignored with a warning.

Hybrid mode

If you set both an API key AND pass a local policy, the local policy overrides the dashboard policy and you get a loud WARN log on init:

WARNING: controlzero: manual policy override detected. ...

This is intentional: it makes accidental prod bypass impossible to miss. For prod environments, opt into strict mode to raise instead:

cz = Client(api_key="cz_live_...", policy=local_policy, strict_hosted=True)
# RuntimeError: manual policy override detected ...

Framework examples

Full integration guides at docs.controlzero.ai/sdk/integrations:

  • LangChain
  • LangGraph
  • CrewAI
  • OpenAI Agents SDK
  • Anthropic tool use
  • Pydantic AI
  • AutoGen
  • MCP servers
  • Raw HTTP / no framework

Hosted mode

When you want a dashboard, audit search, team policies, and approval workflows, sign up at controlzero.ai and set the API key:

import os
os.environ["CONTROLZERO_API_KEY"] = "cz_live_..."

from controlzero import Client
cz = Client()  # picks up the API key from env, audit ships remote

License

Apache 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

controlzero-1.4.0.tar.gz (140.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

controlzero-1.4.0-py3-none-any.whl (136.6 kB view details)

Uploaded Python 3

File details

Details for the file controlzero-1.4.0.tar.gz.

File metadata

  • Download URL: controlzero-1.4.0.tar.gz
  • Upload date:
  • Size: 140.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for controlzero-1.4.0.tar.gz
Algorithm Hash digest
SHA256 8372939ad2a78ec229b198d0fd72f39823f1079be87fa07527ef0a8f6d8cdb16
MD5 e58b1847a156eb9d269b50e06596fa12
BLAKE2b-256 99162b2897c8f9cdb0d81bf5877d1517a8c94f01541e4e9b61f6fea1d0569127

See more details on using hashes here.

File details

Details for the file controlzero-1.4.0-py3-none-any.whl.

File metadata

  • Download URL: controlzero-1.4.0-py3-none-any.whl
  • Upload date:
  • Size: 136.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for controlzero-1.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b2ec1d2f1bc0a582061c0ab5cf3ed54c9ca0412a9aff04e8927173bdeff2d967
MD5 0a5a03d8dff6626526f10f9789cdf23d
BLAKE2b-256 1621aa8ff5993367874792957822d3430f1f3987e79f4710b778ff3286bfb59f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page