Governance (spec.governance)¶
spec.governance declares a chain of governance plugins on an Agent manifest. A plugin is a class that a library registers and a manifest names. Each governance plugin can allow, block, modify, or ask a human before a tool call or LLM call runs. It sees the result or error again when it comes back.
Write a chain to stop undeclared or destructive tool calls. Also write one to require human in the loop (HITL) approval, or to set a recovery policy for engine errors.
This page extends the Agent manifest. It is not a YAML kind.
Minimal working chain. It blocks any tool the LLM call did not declare:
spec:
governance:
- gov_no_undeclared_tool
- Entry syntax: plugin-bindings.md.
- Schema:
governance-binding.schema.yaml. - Developer contract: runtime/docs/dev/contracts/governance.md.
- Retries, circuit breaker,
error_policydefaults, and logging: reliability.md.
Chain¶
spec.governance is an iptables-style chain. Plugins run in list order. BLOCK stops the chain and returns that error. ALLOW passes control to the next plugin.
spec.observability differs: it is a sequence, and every plugin always runs.
Two hook points carry governance decisions:
- Egress runs before a call leaves the agent (
TOOL_CALL,LLM_CALL). The egress chain can allow, block, or ask a human. - Ingress runs when a result or an engine
ERRORcomes back, before it enters the agent's working memory.
| Layer | When | Who |
|---|---|---|
| Infra retry | Inside the LLM HTTP POST or tool invocation | spec.control.retry |
| Circuit breaker | After infra retries on unavailable |
Library plugin via spec.control.circuit_breaker (default threshold) |
| Egress chain | Before the engine call (TOOL_CALL, LLM_CALL) |
Plugins in spec.governance[] |
Ingress error_policy |
After _end, on engine ERROR |
retry_on_error plugin, if installed |
Do not put retry budgets on the egress chain. Infra retry re-issues the same call. Ingress error_policy.transient: retry schedules a new envelope step, up to max_gov_retries. Engine retry defaults: reliability.md.
Without error_recovery_plugin, an ERROR follows gov_ingress_profile (default PERMISSIVE, which allows). The kernel does not interpret error_policy: it is the plugin's config. The recovery plugin is installed on the ingress chain. It is not a kernel slot.
Shipped plugins¶
| Plugin | Role | Card |
|---|---|---|
gov_no_undeclared_tool |
Egress BLOCK if the tool name was not in this LLM call's tools list. |
no-undeclared-tool.md |
retry_on_error |
Ingress: error_policy.<class> maps to allow, retry, block, or skip. Egress always passes. |
retry-on-error.md |
backtrack_on_error |
Ingress: retries an identical engine error, then requests a session rollback once the repeat threshold is reached. Configure it with a backtrack stanza key. |
governance README |
sample_governance (alias of sample) |
HITL before a tool call or before a tool result enters working memory. Also provides destructive-tool profiles. | sample-governance.md |
Any plugin registered as type: governance in a library manifest can join the chain. The schema checks only the shape (a bare id or a single-key map). An unknown id fails when the agent is built.
The default chain is empty ([]).
Error recovery¶
error_recovery_plugin and error_policy can sit on any stanza, like hitl_on_tool. The parser flattens them and installs the named plugin on the ingress chain. The kernel never stores a plugin instance of its own.
governance:
- gov_no_undeclared_tool
- retry_on_error:
error_recovery_plugin: retry_on_error
error_policy:
transient: retry
unavailable: retry
application: allow
fatal: block
The with-hardened overlay sets this up for you. It does five things:
- Appends both governance plugins.
- Merges
control.retryandcontrol.circuit_breaker, which loads thethresholdcircuit-breaker plugin. - Sets
spec.budget.max_llm_calls: 50. - Sets
spec.budget.max_tool_calls: 100. - Caps the dispatch loop at
design_pattern.params.max_steps: 512.
Details: reliability.md.
Trace events¶
Each ingress or egress decision is a kind: governance_decision record in native events.jsonl. Typed failures also carry failure_class, failure_code, and retry_attempts. Infra re-attempts are logs on mas.runtime.reliability, not governance events. See reliability.md § Logging.
Stanza keys read by the runtime¶
Besides the plugin's own constructor arguments, the runtime reads these keys from any stanza in the chain. Each key applies to the whole agent.
When two stanzas set the same key, the first stanza in list order wins. The policies and ingress_plugins lists are concatenated instead.
| Key | Default | Effect |
|---|---|---|
hitl_on_tool |
false |
Ask a human before a tool call runs (egress). |
hitl_on_tool_result |
false |
Ask a human before a tool result enters working memory (ingress). |
hitl_once_per_turn |
false |
After one tool call is approved in a turn, later tool calls in that turn skip the prompt. |
hitl_mode |
interactive |
Who answers HITL prompts: interactive (terminal operator), auto-approve, or auto-deny. A non-interactive session with interactive auto-approves. |
gov_policy_profile |
BLOCK_DESTRUCTIVE |
Built-in policy for destructive tools: PERMISSIVE, BLOCK_DESTRUCTIVE, HITL_DESTRUCTIVE, LOG_ALL, MODIFY_DESTRUCTIVE, TERMINATE_DESTRUCTIVE, SKIP_DESTRUCTIVE, BLACKLIST_DESTRUCTIVE. |
gov_block_destructive / gov_trigger_destructive |
false |
Turn the destructive-tool policy on. |
gov_ingress_profile |
PERMISSIVE |
Ingress decision on engine ERROR when no recovery plugin is installed: PERMISSIVE, RETRY_ON_ERROR, BLOCK_ON_ERROR, SKIP_ON_ERROR. |
max_gov_retries |
2 |
Cap on governance-requested retries of one step. |
error_recovery_plugin, error_policy |
unset | Ingress recovery plugin and its policy table (see Error recovery). |
backtrack |
unset | Config for backtrack_on_error: repeat_threshold, max_backtracks_per_session, steps (integers >= 1) and on_cap_reached (hitl, terminate, stop_backtracking). |
If no governance plugin is named but hitl_on_tool, hitl_on_tool_result, or gov_trigger_destructive is set, the runtime installs sample_governance with those flags.
Smallest HITL chain. A terminal operator approves each tool call:
governance:
- sample_governance:
hitl_on_tool: true
BLOCK (and hitl_mode: auto-deny) refuses the tool and ends the turn with
that denial as the user-visible answer. Optional steering is appended to the
denial. SKIP injects optional steering as the tool result and lets the model
continue. Walkthrough: Tutorial 14.
See also¶
- Tutorial 14: governance and HITL
- Agent manifest: where
spec.governancelives - Plugin bindings: entry syntax
- Overlay manifest: add governance to an existing agent