Adding Governance
Governance in Waxell has two layers, and most teams grow from the first into the second:
- What the agent author declares — per-agent caps in
waxell.yaml. Fast to set, scoped to one agent, and enough on day one. - What the operator configures — policies in the engine, scoped across agents, workflows, tools, models, and teams, evaluated server-side.
The second layer is the enforcement backbone: an agent can't opt out of a policy by editing its own manifest. If you're governing more than a couple of agents, that's where you want the rules to live.
Per-agent limits
Declare caps on the agent:
agents:
- name: email_sender
max_budget_usd: 2.00 # hard USD cap (default 10.00)
max_turns: 15 # agent turns (default 25)
timeout_seconds: 120 # wall time
Set them explicitly — the defaults are generous, and a looping agent will spend to them.
For a spawned child, caps are set at the call site and debit from the parent:
findings = await ctx.spawn(
"research_agent",
inputs={"topic": topic},
budget_usd=2.00,
timeout_seconds=300,
)
Approval requirements
Approval is a property of the domain action:
domains:
- name: accounts
actions:
- name: delete_account
requires_approval: true
When the agent calls it, the run pauses with
PausedReason.awaiting_approval and holds no compute until a human decides. It
resumes from the checkpoint — the work already done is not repeated.
This is the right place for it: the approval attaches to the action, so every
agent that can call accounts.delete_account inherits the requirement, and you
can't forget it on the fifth agent.
Where policies are evaluated
Policies run at three points, and the differences matter:
| When | Sees | Typical use |
|---|---|---|
| Before the run | Inputs, agent identity, caller | Block disallowed inputs; require approval up front |
| Mid-run | Each tool call, before it executes | Stop a specific action — a write, a spend, an external send |
| After the run | Full output and span tree | Redact, flag for review, raise an incident |
Mid-run is the one people underestimate: an agent that decided to do something disallowed is stopped at the call, not cleaned up afterwards.
A blocked run is a first-class outcome — it finishes in the terminal BLOCKED
state with a recorded decision and an ExecutionIncident. It does not raise,
so there is nothing to try/except. Code that polls for only COMPLETED or
FAILED hangs forever; see run states.
Policies: the engine behind all of this
Limits and approvals cover the agent you're writing. Policies are the layer above — rules an operator sets that apply across agents, scoped to a tenant, agent, workflow, tool, model, user, or team, and evaluated server-side at the three points above.
Waxell ships 49 policy categories. A few you'll reach for early:
| Category | Governs |
|---|---|
| Budget | Token and dollar budgets — per-run, daily, monthly |
| Rate Limit | Request rates and concurrency per agent, user, or team |
| Content | Input/output scanning for PII, credentials, injection |
| Data Access | Which sources an agent may read or write |
| Network | Outbound domain allowlists |
| Scope | Blast radius — records modified, transaction amounts |
| Approval | What requires a human before it proceeds |
| Kill Switch | Emergency stop on error rate or anomaly |
The full set — including OWASP LLM Top 10, GDPR, HIPAA, SOC 2, ISO 42001, and NIST AI RMF categories — is in Policy Categories & Templates.
Every check returns an action: allow, warn, redact, throttle, block, or
skip. See Policy & Governance for how the
evaluation and the actions work.
Policy as code
Define policies alongside your agents and push them like any other artifact:
from waxell_sdk import policy
outreach_budget = policy(
name="outreach_budget",
category="budget",
scope={"agents": ["outreach_agent"]},
rules={
"per_workflow_token_limit": 50_000,
"per_workflow_cost_limit": 1.00,
},
description="Budget ceiling for outreach agent runs.",
)
wax -p prod policies push ./governance/ --dry-run # show the diff
wax -p prod policies push ./governance/ # apply
This creates real, scoped policy records — the same objects the Governance panel
edits. Inspect what's live with wax -p prod policies list and
wax -p prod policies show <name>.
Scope is the important field. {"agents": ["outreach_agent"]} narrows a policy
to one agent; omit it and the policy applies tenant-wide. You can also scope by
workflows, tools, models, user_groups, and more.
Promoting policy between environments
Policy bundles move a curated set of policies between tenants — a golden config rollout, or a snapshot before a change:
| Endpoint | Purpose |
|---|---|
GET /v1/governance/bundles/export/ | Current policy set as a versioned JSON bundle |
POST /v1/governance/bundles/preview/ | Dry-run import — per-policy diff, writes nothing |
POST /v1/governance/bundles/import/ | Apply, with mode=merge|replace and conflict=skip|overwrite |
Imports auto-snapshot the affected policies into PolicyVersion first, so a
rollout is reversible.
Test before you enforce
Two things worth doing before a policy goes live:
- Dry-run a draft against real traffic to see what it would have caught, before it blocks anything.
- Check for conflicts — overlapping scopes where two policies disagree surface as a conflict rather than as a mystery block in production.
Both are in the Governance panel alongside the policy editor.
The audit trail
Every run is recorded automatically. There is nothing to enable and nothing to instrument:
| Artifact | Holds |
|---|---|
| Span tree | Every LLM, tool, and domain call — nested, timed, errors marked |
LlmCallRecord | Model, tokens in/out, cost, provider instance |
| Policy decisions | What evaluated, what it decided, why |
ExecutionIncident | Errors, policy blocks, budget stops |
| Audit log | Who or what triggered the run, under which identity |
A failed or blocked run is recorded as fully as a successful one.
Inspect from the CLI:
wax -p prod traces list --hours 24 --agent email_sender
wax -p prod traces show <trace_id>
Or open Observe → Runs for the same trace with the span tree rendered.
Next steps
- Policy Categories & Templates — all 49 categories
- Policy & Governance — how evaluation and actions work
- How the Runtime Works — where governance sits in a run
- Production Guide — deploy with governance