Back to blog
·5 min read

Runtime Policy Enforcement for AI Agents

Static guardrails work for chatbots. You define a system prompt, add content filters, and monitor outputs. The model generates text, and your filters catch problems before the text reaches the user.

This breaks down for autonomous agents. An agent does not just generate text — it executes actions. It calls APIs, moves data, triggers workflows, and interacts with external systems. Content filters cannot gate these actions because the actions are not content. They are function calls, HTTP requests, and database writes.

Why static guardrails fail

Consider a trading agent with this guardrail:

# System prompt guardrail
"You may only trade AAPL, MSFT, and GOOGL.
Maximum position size: 1,000 shares.
Do not trade outside market hours."

This is a suggestion, not enforcement. The LLM may follow it. It may not. There is no mechanism to prevent the agent from calling execute_trade(symbol="NVDA", qty=50000) if the model decides to. The guardrail exists in the prompt, not in the execution path.

Three failure modes:

  • Prompt injection — a crafted input convinces the agent to ignore constraints
  • Emergent behavior — the agent finds an unexpected path that bypasses stated limits
  • Tool-level gaps — the guardrail filters text output, but the agent calls tools directly

Runtime enforcement: a different architecture

Runtime enforcement moves policy from the prompt to the execution path. Instead of telling the agent what it should not do, you require cryptographic authorization before any action executes.

Agent wants to: execute_trade(AAPL, 50000)
↓ Submit to enforcement gateway
Gateway evaluates: quantity 50000 exceeds max 10000
→ Decision: CLAMP (quantity → 10000)
Gateway issues: signed release token
↓ Agent receives clamped action
Agent executes: execute_trade(AAPL, 10000)
↓ Evidence recorded in hash-chained ledger

The key difference: the enforcement gateway is not a suggestion. It is a cryptographic gate. Without a valid release token, the action does not execute. The agent cannot bypass it because the token is verified independently at the execution layer.

Three decisions, three outcomes

Every action submitted to the enforcement gateway receives one of three decisions:

ALLOWAction proceeds as requested. Release token issued as proof of authorization.
CLAMPAction adjusted to safe bounds. The agent uses the modified action from the response.
DENYAction rejected. No release token. The agent does not proceed.

CLAMP is what makes this practical. Instead of a binary allow/deny, the gateway can adjust parameters to safe bounds. The agent still accomplishes its goal — just within policy limits. This reduces friction without reducing safety.

The evidence chain

Every decision — ALLOW, CLAMP, or DENY — is recorded in a hash-chained evidence ledger. Each record links to the previous via SHA-256 hash. Modify any record and every subsequent hash becomes invalid.

This creates a complete, tamper-evident record of every agent action and every governance decision. Auditors can verify the chain independently. Compliance teams can export evidence bundles. Regulators can inspect the record without access to the running system.

Implementation

Adding enforcement to an existing agent takes three lines of code:

from kevros_governance import GovernanceClient

client = GovernanceClient(api_key="kvrs_...")

# Before any agent action:
result = client.verify(
    action_type="trade",
    action_payload={"symbol": "AAPL", "quantity": 50000},
    agent_id="trading-agent",
    policy_context={"max_values": {"quantity": 10000}},
)

if result.decision == "DENY":
    # Do not proceed
    pass
else:
    # Use result.applied_action (may be clamped)
    execute_trade(**result.applied_action)
See ALLOW, CLAMP, and DENY live

The API console shows all three decisions with real API responses. No signup required for pre-rendered mode.

Open the API console