Policy and governance
A plane, not a layer. One place decides what an agent may do, under what conditions, and how much. Human approval is one of its three answers.
Policy and governance
The cross-cutting plane. It has no number, because it is not a step in the path.
Permissions answer "can it". Policies answer "under what conditions". Limits answer "how much".
A plane, not a layer
The six layers are a path. A request enters at the top and leaves at the bottom. Policy is not on that path. It is asked a question at three points, and it answers in one word.
Drawing it as a band between the intelligence layer and the tools would say that the tool call is the only gate. It is not. A scheduled run for a domain over its budget must be stopped before it dispatches, and that decision happens before any tool exists.
Three checkpoints
| Checkpoint | When | Question | What a refusal costs |
|---|---|---|---|
| Admission | Before a run dispatches | May this principal run this agent, and is the domain inside its limits? | Nothing has run, so nothing is wasted |
| Action | On every tool call | May this action happen, with these arguments, on this record? | One call is refused or gated |
| Accrual | As cost and count add up | Is the run still inside its budget? | The run stops at a step boundary |
A check only at admission is the failure this plane exists to prevent. An agent that reaches a sensitive action through a different workflow, a different skill or a later turn must meet the same gate it would have met on the first path.
The decision
Three words, and there is no fourth.
allow the call proceeds
deny the call is refused, and the agent is told why
require_approval the run pauses, and a person decides
Precedence is fixed. Deny beats require approval, and require approval beats allow. Anything not granted is denied.
There is no priority field. Two rules at the same priority is undefined behaviour, and the strongest decision is the only safe tie-break.
An open decision set becomes a rules language, and a rules language is new infrastructure. A condition on the arguments is expressive enough for the cases we have.
Permissions
Every action carries one principal, minted at admission and threaded everywhere.
domain · person · agent · run
Three rules govern it.
- A grant is an intersection, never a union. An agent may do what its spec names and what its principal may do. It never exceeds the person it runs for.
- A triggered run has no person. It runs as a service principal with an explicit grant, and that grant is usually narrower than any person's.
- An approval cannot grant a permission the approver does not hold. Without this rule, approval is a privilege escalation path.
Permissions need no table. An agent's permission surface is its tool list and its scopes. A person's rights are their roles. The plane computes the intersection, and stores neither side.
Policies
A policy is a row, not code in an agent.
policy
name
scope the whole company, or one domain, or one agent
action the tool name, or a domain of actions
conditions over the arguments and the target record
decision allow | deny | require_approval
Bind a policy to an action, not to an agent. A rule that reads agent = CostOps AND action = send_email re-creates the fragmentation this plane removes. The subject defaults to every agent, and an agent scope is an optional narrowing.
Four that any company needs.
action = send_email AND recipient_is_external → require_approval
action = update_lifecycle AND target = customer → require_approval
action = spend AND amount > threshold → require_approval
action = delete_record → deny
What is not a policy: "require evidence before qualifying a lead" is not a decision. It is a condition on the arguments, or a check in the tool handler. Keep it there.
Human approval
The run pauses. It does not poll, and it does not proceed on a guess.
tool call → policy → require_approval → approval row → the run waits
│
a person decides
/ \
approve reject
│ │
execute the run is told, and continues or stops
Human approval is a policy decision, not agent code. That is the whole point of the plane. An agent does not carry a rule about when to ask a person. The plane decides, and the same rule binds every agent.
An approval request carries enough for a person to decide without opening the run.
approval
requested action the tool and its arguments
agent · workflow · run
target the record it changes
reason the policy that matched
risk low | medium | high
proposed change the exact content, rendered
context why the agent wants it
expires at the TTL
decision approve | reject | expired, and who decided
Limits
The plane owns the definitions. It does not own the enforcement.
| Shape | Examples | Enforced by |
|---|---|---|
| Rate | Concurrency, runs per minute, debounce | The execution engine's flow control |
| Cost | Tokens, spend per run, spend per domain per day | The cost meter, at accrual |
| Count | Tool calls per run, records written per run | The run itself, counted at action |
A second rate limiter next to the engine, or a second meter next to the cost meter, is exactly the new infrastructure this design refuses. A limit row states the ceiling and names its owner. The existing machinery reads it.
The decision log
Every evaluation writes one row: the principal, the action, the argument hash, the policy that matched, and the decision.
Governance with no decision log is half a plane, and the log is the part an audit asks for. It also answers the question a person actually has, which is "why did it not do that". The answer is a policy name, not a silence.
Rules
- The policy engine never calls a model. It is deterministic and it is fast. A model call would be a second hop, and a non-deterministic decision cannot be audited.
- Tenant isolation stays with row-level security. The plane carries the principal and may deny early, so it is defence in depth. The database is still the boundary.
- A denial the agent may see is a tool result. A capability the agent must never hold is absent from its registry subset instead.
- Policy is evaluated on the agent's behalf, never by the agent. The tool invoker asks. The agent cannot ask for a different answer.
- One plane, every path. A rule written once binds every agent and every workflow, and none of them carries it.
Data model
| Table | Holds |
|---|---|
policies | One rule: scope, action, conditions, decision. |
limits | One ceiling: scope, metric, window, value. |
policy_decisions | One evaluation: principal, action, argument hash, matched policy, decision. |
approvals | One pending human decision, its request, its TTL and its outcome. |
Risks
| Risk | Mitigation |
|---|---|
| A per-call check adds latency on the hot path | The rule set per domain is small and cacheable, and the decision is a match, never a model call |
| The condition language grows until it is a rules engine | The decision set is closed at three. A case that needs a fourth is a handler check, reviewed as a design change |
| Approvals arrive faster than a person answers, and every run stalls | Only write and send tools can be gated, and a TTL expires a request rather than holding a run open |
| A policy is written that no agent can satisfy, and the failure is silent | The decision log names the policy on every denial |
| The plane becomes the place tenancy is enforced | Row-level security stays the boundary. This is stated here and enforced in review |
| A person approves without reading, because every action asks | Gate by risk, not by habit. An approval queue that is always full is an approval queue nobody reads |
Open questions
- Who authors a policy? Admins only, or a role of its own?
- Does a policy change apply to a run already in flight, or only to the next one? A version pin matches agent specs, and it costs one column.
- Do we need a dry-run mode that logs a decision without enforcing it? It is the only safe way to introduce a rule to live operations.
- Is require approval per call, or per run for the same action and target? Ten identical approvals is a worse product than one.
- Can a policy escalate rather than block, for example approve below a threshold and ask above it? That is two rows today, and it may deserve one.
Diagram source. ac-docs/diagrams/mission-control-layers.drawio, page mission-control-policy.
Edit that page, then run ./scripts/export-diagrams.sh mission-control-layers.
Update this page and the diagram together.