Anthropic Integration
Add governance to your Anthropic Claude calls with one line of code. The SDK wraps your Anthropic client and automatically enforces whatever policies you have defined in the Control Zero dashboard.
Setup
pip install controlzero anthropic
import controlzero
from controlzero.integrations.anthropic import wrap_anthropic
import anthropic
cz = controlzero.init()
client = wrap_anthropic(anthropic.Anthropic(), cz)
# Use client exactly as before -- all calls are now governed
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
print(response.content[0].text)
Two lines added. Zero changes to your application logic.
What Gets Enforced Automatically
| API Method | Policy Action | Policy Resource |
|---|---|---|
messages.create(model="claude-sonnet-4-20250514") | llm.generate | model/claude-sonnet-4-20250514 |
messages.stream(model="claude-sonnet-4-20250514") | llm.generate | model/claude-sonnet-4-20250514 |
The wrapper extracts the model parameter, checks it against your policies, and blocks the call if denied.
Example Policy
Define this in the Control Zero dashboard:
{
"name": "anthropic-model-governance",
"rules": [
{ "effect": "allow", "action": "llm.generate", "resource": "model/claude-sonnet-4-20250514" },
{ "effect": "deny", "action": "llm.generate", "resource": "model/claude-*-opus*" },
{ "effect": "deny", "action": "llm.generate", "resource": "model/*" }
]
}
What happens at runtime:
# ALLOWED -- Sonnet is explicitly allowed
client.messages.create(model="claude-sonnet-4-20250514", ...)
# BLOCKED -- Opus is denied
client.messages.create(model="claude-opus-4-20250514", ...)
# Raises PolicyDeniedError
# Also works with streaming
for event in client.messages.stream(model="claude-sonnet-4-20250514", ...):
pass # ALLOWED
Handling Denied Actions
try:
response = client.messages.create(
model="claude-opus-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
except controlzero.PolicyDeniedError:
# Fall back to Sonnet
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
Controlling Tool Use
When Claude calls tools, you can govern which tools are allowed. Define tool policies in the dashboard:
{
"name": "claude-tool-governance",
"rules": [
{ "effect": "allow", "action": "llm.generate", "resource": "model/claude-sonnet-4-20250514" },
{ "effect": "allow", "action": "tool.call", "resource": "tool/search_web" },
{ "effect": "deny", "action": "tool.call", "resource": "tool/send_email" },
{ "effect": "deny", "action": "tool.call", "resource": "tool/database_query" }
]
}
For tool enforcement, use the enforce() method in your tool handler:
def handle_tool_call(tool_name: str, tool_input: dict) -> str:
# The SDK checks: is tool/{tool_name} allowed by the dashboard policy?
cz.enforce(action="tool.call", resource=f"tool/{tool_name}")
return execute_tool(tool_name, tool_input)
Per-Agent Wrapping
analyst_client = wrap_anthropic(anthropic.Anthropic(), cz, agent_id="analyst")
support_client = wrap_anthropic(anthropic.Anthropic(), cz, agent_id="support")
Using the Secrets Vault
cz = controlzero.ControlZero(secrets_enabled=True)
cz.initialize()
anthropic_key = cz.get_secret("anthropic")
client = wrap_anthropic(anthropic.Anthropic(api_key=anthropic_key), cz)
Next Steps
- OpenAI Integration -- Same pattern for OpenAI API calls.
- LangChain Integration -- Callback handler for LangChain.
- Customer Support Guide -- Build a policy-enforced support agent with Claude.
- MCP Tool Control -- Control MCP tools with Claude Code.