Give your agents a job,
not an API key.
An agent in your model is an actor like any other.
It holds the operations you grant it, under the policies you already wrote. And every action it takes is recorded with whose authority it used.
Its tools
checking…
Payables queue
8 waiting
0
approved
0
to the CFO
Change that one number and the split moves. No redeploy, no prompt edit, nothing touched on the agent.
Before anything runs, read what governs the agent itself. Three of its eight tools reach an act something governs. The other five — including the one that can move money out — reach nothing at all.
The finding
Most of your agent is ungoverned.
Not badly governed — ungoverned. No rule about whether it may, no flag, no record that it ever did. Most teams have never seen that figure for an agent they are already running, because nothing they own is in a position to compute it. A framework does not know what an approval limit is.
The gap is not that agents are dangerous. It is that your organization already has answers to all of this for people — positions, delegated limits, escalation, approval, a record — and none of it reaches the agent, because the agent was never in the model.
3 of 8 of this agent's tools are governed by something.
The denominator is this agent's tools, so it moves per agent and per graph.
Every tool this agent has, and nothing hidden. payment.void and ledger.adjust can both move money out, and neither has a rule about who may.
Action
Approve Invoice
June Alcott
Chief Financial Officer
Accounts Payable Agent
anthropic/claude-sonnet-5
The same word on both arrows. Nothing was invented for the one on the right.
So one act records both
Which agent did it, and on whose authority. Different questions — an audit that answers only one answers neither well.
The model
An agent is an actor. Same edges, same rules.
The edge that gives a person their work admits an agent unchanged, so every report, lens and audit query you already have keeps working. None of them had two code paths to begin with.
Reassigning work between the CFO and an agent is a rewrite of one arrow.
Not a migration, not a new integration, and not a pull request against a prompt — the agent’s instructions live in the graph too, so changing how it behaves is a change to your model.
Enforcement
The gate is outside the model.
Every guardrail story you have heard is a prompt asking a model nicely. This is not that. The decision is made against your graph, before the tool body runs, by code the model cannot reach or reason with.
It cannot call what it was not granted. Tools are derived from the operations an agent owns, so one it has no grant for does not exist on it.
The rule is judged on the graph. Not on what the caller claimed. An agent that calls the approval tool with an invented amount is judged on the real one.
It cannot nominate itself. There is deliberately no “who is asking” parameter, so an agent cannot describe an actor and route its own work to itself.
Being sent somewhere is not permission to go. A rule that routes work is a refusal here, not information — that is how anything bypasses an escalation by ignoring where it was sent.
INV-0004 Proseware Cloud $9,800 Performed
$9,800 is under the limit, so the rule delegates it.
allow → the agent
INV-0006 Woodgrove Facilities $10,000 Assigned
$10,000 is not under $10,000. The rule delegates what is below the limit; this sits exactly on it.
route → Chief Financial Officer
Returned to the model
“Approving this invoice is reserved to the CFO. It has been assigned to them.”
INV-0008 Fourth Coffee Group $42,000 Assigned
Over the limit by a wide margin, and reserved by the same branch of the same rule.
route → Chief Financial Officer
Returned to the model
“Approving this invoice is reserved to the CFO. It has been assigned to them.”
Every call ends in one of four — performed, assigned, blocked, or unevaluable when two rules tie and nothing can break it. A system that always has an answer is one that is sometimes making it up.
import { Operation } from "@dna/agent-ops";
export const approveInvoice = Operation("invoice.approve", {
target: (args) => args.invoiceId,
perform: async (args) => { /* your code, untouched */ },
});That is everything. The wrapper resolves the target and refuses before perform runs, the tool body is not touched, no framework is replaced, and a tool that names no operation is left alone rather than reported as broken.
Install and trust
One wrapper,
and nothing else changes.
Two questions, and they are really one: what does this cost me to try, and what does it do to the thing I am already running in production. Each answer below is a property the enforcement package asserts about itself, not a promise we are making on its behalf.
No network call at the moment of decision. The rules are a local snapshot, not a fetcher — it could not call out even in principle. Your latency is unchanged, and your agent does not stop when we do.
Staleness never permits. Reported on every verdict and bounded by a limit you set. Refusing on it would make a slow refresh your outage; permitting on it would make the bound an attack.
Drawing fails open, binding fails closed. What may be offered leaves your agent as it was. What may happen refuses. A thing that permits when it cannot decide authorizes nothing.
Or install nothing at all.
Claude, Cursor, your own loop — any MCP client reaches the same model through the same tools, with no integration to build. And asking is free: an agent that can only read is an inspector, and inspectors are unlimited on every plan, forever.
FAQ
Do I have to rewrite my agents to use this?
No. Wrap the tools you already have — each one names the operation it performs and what it acts on, the same word the Overlay stamps on a control, and the body is untouched. Or wrap nothing at all and point an MCP client at your model, which is free and unlimited for reading.
Does the model decide whether it is allowed?
No, and that is the whole design. Tools are derived from the operations an agent owns, so one it was not granted does not exist on it. The governing rules are re-checked when a tool is called, judged against what the graph says the target is rather than what the caller claimed, and there is deliberately no parameter naming who is asking — a caller that could describe its own actor could route its own work to itself.
Can an agent change the rules that govern it?
No. An agent credential may read and it may act; it may never put a rule in force and it may never change one. An agent that can ratify its own grants has no grants. A machine may observe; a person decides.
How do you price an agent?
There is no new meter. An agent that may act is an editor seat, at the same price as a person — if the two are interchangeable, charging differently for them would contradict the argument on this page. An agent that only reads is an inspector, and inspectors are never metered. Bring your own model key. See the full ladder →
Is this ready for production?
It is in build, which is a weaker claim than the Overlay’s early access and deliberately so. The enforcement underneath it ships today and the runtime executes a real queue under real policy. There is no console yet, and identity for external agents arriving over MCP is not finished — so we set design partners up by hand and tell them exactly which half they are getting.
Run it on an agent you already have.
Bring the one you are least comfortable explaining to your auditor. The interesting part is usually how few of its tools anything governs, and how quickly that stops being a surprise once somebody has seen the number.
We are looking for design partners running agents they cannot fully answer for yet.
Got it, thank you.
We read every one of these by hand. Expect a reply from a person, usually within a day.