Governance Plane

GovernancePlane is the runtime's last line of defense: hard-stop limits enforced outside agent code so the agent cannot bypass them via recovery. When a limit configured with on_breach="terminate" is exceeded, the orchestrator raises GovernanceBreachError, which the session marks as FAILED and re-raises without going through the failure classifier or the recovery loop.

This is the technical primitive auditors expect for EU AI Act deployments — Article 14 (human oversight via stopping conditions), Article 15 (robustness / fail-safes), and Article 26 (deployer monitoring + reporting). See the technical control crosswalk in Compliance Mapping for how runtime primitives support audit evidence.

When to use this

When NOT to use this

Quickstart

from techrevati.runtime import (
    AgentSession,
    GovernancePlane,
    MaxBudgetLimit,
    MaxConsecutiveFailuresLimit,
    MaxIterationsLimit,
    MaxToolCallsLimit,
)

plane = GovernancePlane(
    limits=(
        MaxIterationsLimit(value=25, on_breach="terminate"),
        MaxBudgetLimit(value=5.00, on_breach="terminate"),
        MaxConsecutiveFailuresLimit(value=3, on_breach="terminate"),
        MaxToolCallsLimit(value=100, on_breach="alert"),
    ),
)

session = AgentSession(role="writer", phase="draft", governance=plane)

The orchestrator ticks the plane's counters at three points:

0.3.0rc1 supports only scope="session". Thread-level and project-level governance need shared cross-session state, so those scopes fail closed until they are implemented end-to-end.

When a GovernancePlane is passed to AgentSession, the plane is used as immutable limit configuration. Each session() / asession() call receives a fresh GovernanceState, so counters do not leak between separate sessions opened from the same factory.

The four built-in limits

MaxIterationsLimit

Caps total turns in the session. Distinct from AgentSession.max_iterations — that one raises a recoverable MaxIterationsExceededError that caller code can catch inside the session. If that exception escapes the session context, the terminal agent.failed event still uses failure_class="governance_breach" because it is a runaway-loop control-plane stop.

MaxIterationsLimit(value=25, on_breach="terminate")

MaxBudgetLimit

Caps cumulative cost in USD. Distinct from UsageLimits.cost_usd_max — that one is recoverable; this one is terminal.

MaxBudgetLimit(value=5.00, on_breach="terminate")

MaxConsecutiveFailuresLimit

Counts consecutive failures. A single successful turn resets the counter to zero. Catches "the agent retries the same broken thing forever" failure modes that per-step retry budgets alone do not.

MaxConsecutiveFailuresLimit(value=3, on_breach="terminate")

MaxToolCallsLimit

Caps total tool invocations in the session. Distinct from UsageLimits.tool_calls_max only in being terminal.

MaxToolCallsLimit(value=100, on_breach="alert")

on_breach modes

Mode Behavior
"terminate" (default) Raises GovernanceBreachError. Worker → FAILED. Recovery loop is NOT invoked.
"alert" Emits a governance.alert event on every breached evaluation. Session continues.

Rolling out a new limit safely: deploy with "alert" for 1–2 weeks, observe the governance.alert event rate, then flip to "terminate".

Event surface

Two new AgentEventName values surface in 0.3.0:

Both carry data = {limit_name, observed, ceiling, scope} for sink serialization.

Composing with UsageLimits

These two primitives are not redundant — they sit at different layers.

sess = AgentSession(
    role="writer",
    phase="draft",
    # Soft cap: agent code can catch UsageLimitExceededError and react.
    usage_limits=UsageLimits(total_tokens_max=200_000),
    # Hard cap: governance breach terminates the session regardless.
    governance=GovernancePlane(
        limits=(MaxBudgetLimit(value=10.00, on_breach="terminate"),),
    ),
)

A common pattern is: usage_limits cap at 80% of the budget, governance hard-stop at 100%. The agent gets a recoverable warning before the session dies.

Tuning the knobs

Knob Reasonable range Notes
MaxIterationsLimit.value 10-50 for production loops Same default as AgentSession.
MaxBudgetLimit.value per-customer / per-session limit Pair with UsageLimits.cost_usd_max at 80%.
MaxConsecutiveFailuresLimit.value 2–5 Below 2 is twitchy; above 5 hides real reliability bugs.
MaxToolCallsLimit.value 5×–10× expected Useful as an alert before flipping to terminate.
on_breach="alert" Always start here for new limits Measure first, terminate second.

Anti-patterns

Sources