Skip to content

Tutorial 36: 2-Line Governance with govern()

Time: 10 minutes · Level: Beginner · Prerequisites: pip install agent-governance-toolkit

What You'll Build

A governed AI tool with full policy enforcement, audit logging, and denial handling — in just 2 lines of code.

The Problem

Traditional AGT integration requires understanding multiple components and how to wire them:

# ❌ The old way (10+ lines)
from agentmesh.governance import PolicyEngine, Policy, AuditLog

engine = PolicyEngine(conflict_strategy="deny_overrides")
engine.load_yaml(policy_yaml)
audit = AuditLog()
context = {"action": {"type": action}, ...}
decision = engine.evaluate("my-agent", context)
audit.log("policy_evaluation", "my-agent", action, outcome=decision.action, ...)
if not decision.allowed:
    raise Exception(f"Denied: {decision.reason}")
result = my_tool(**kwargs)

The Solution

# ✅ The new way (2 lines)
from agentmesh.governance import govern

safe_tool = govern(my_tool, policy="my-policy.yaml")

Example 1: Governed Database Query Tool

from agentmesh.governance import govern

def query_database(action="read", table="users", **filters):
    """Simulate a database query tool."""
    print(f"  Querying {table} ({action}) with filters: {filters}")
    return {"table": table, "action": action, "rows": 42}

# Create the governed version
safe_query = govern(query_database, policy="""
apiVersion: governance.toolkit/v1
name: db-access-policy
agents: ["*"]
default_action: allow
rules:
  - name: block-drop
    condition: "action.type == 'drop'"
    action: deny
    description: "DROP operations are never allowed"
    priority: 100

  - name: block-write-to-audit
    condition: "action.type == 'write' and table.value == 'audit_log'"
    action: deny
    description: "Audit log is append-only — no direct writes"
    priority: 100

  - name: require-approval-for-delete
    condition: "action.type == 'delete'"
    action: require_approval
    approvers: ["dba-team"]
    priority: 50
""")

# ✅ This works
result = safe_query(action="read", table="users", limit=10)
print(f"Result: {result}")

# ❌ This is denied
try:
    safe_query(action="drop", table="users")
except Exception as e:
    print(f"Blocked: {e}")

Output:

  Querying users (read) with filters: {'limit': 10}
Result: {'table': 'users', 'action': 'read', 'rows': 42}
Blocked: Action denied by policy rule 'block-drop': ...

Example 2: Custom Deny Handler

Instead of raising exceptions, handle denials gracefully:

from agentmesh.governance import govern

def send_email(to, subject, body):
    return {"sent": True, "to": to}

safe_send = govern(
    send_email,
    policy="email-policy.yaml",
    on_deny=lambda decision: {
        "sent": False,
        "blocked_by": decision.matched_rule,
        "reason": decision.reason,
    },
)

# If denied, returns the dict instead of raising
result = safe_send(action="send", to="external@gmail.com", subject="Q3 Revenue")
# → {"sent": False, "blocked_by": "block-external-pii", "reason": "..."}

Example 3: File-Based Policy with Extends

from agentmesh.governance import govern

safe_tool = govern(
    my_agent_tool,
    policy="policies/team-policy.yaml",   # loads extends chain automatically
    agent_id="customer-service-agent-1",
)

Example 4: Inspect the Audit Trail

safe_tool = govern(my_tool, policy="policy.yaml")

# Execute some actions
safe_tool(action="read")
safe_tool(action="query")

# Inspect what happened
for entry in safe_tool.audit_log.query():
    print(f"  {entry.action}{entry.outcome} (rule: {entry.data.get('rule', 'none')})")

Example 5: Access the Engine for Advanced Use

safe = govern(my_tool, policy="policy.yaml")

# Direct policy evaluation (bypass the wrapper)
decision = safe.engine.evaluate("my-agent", {
    "action": {"type": "export"},
    "data": {"classification": "restricted"},
})
print(f"Would be: {decision.action} by {decision.matched_rule}")

Quick Reference

Parameter Type Default Description
policy str or Policy required File path, inline YAML, or Policy object
agent_id str "*" Agent identifier for policy evaluation
audit bool True Enable audit logging
on_deny callable None Custom handler (default: raise GovernanceDenied)
approval_handler ApprovalHandler None Human-in-the-loop handler
advisory AdvisoryCheck None Non-deterministic defense-in-depth
conflict_strategy str "deny_overrides" How to resolve rule conflicts

What to Try Next

  • Tutorial 35: Policy composition with extends
  • Tutorial 38: Human-in-the-loop approval workflows
  • Tutorial 39: DLP with attribute ratchets