An ops agent that asks before it acts
An operator gives orders in chat. An operations agent reads the target, asks a gate that holds a policy file, and makes the one call the gate admits, on a live Kubernetes cluster that it reaches only as a scoped service account. Every order ends with the cluster read back, so the last word is what the cluster shows, not what the agent believes.
Allowed, escalated, refused, and always read back
| Order | Outcome | What the record shows |
|---|---|---|
| Which pods are not running in the demo namespace? | read | Answered from the cluster, not from memory. |
| Scale an ordinary workload to 2 | allowed | Made, then read back at once: two replicas asked for, the new pod still starting. |
| Scale the critical freezer to 3 | escalated | actuated: false. The read-back shows the freezer unchanged at 1. |
| Create a workload | allowed | Labeled with how it got there. It runs a command, so it stays up. |
Create a workload labeled tier=critical, in plain language | refused | The model passed the label through; the gate refused it as a claim by the order. Nothing was created. |
| Apply a manifest from a public repository | 1 applied, 2 refused | Decided object by object. A Service is refused by kind before the gate: three objects, two decisions. |
| Is the cluster what the repository says? | true | Both sides answered and agree. If either is silent, the answer is null, never a quiet "in sync". |
Three rules, each with its reason written down
For an existing workload, the gate decides against labels read off the live object, so an order cannot choose its own answer. A create has no live object: its labels can only come from the order, and the gate is told so. Deny outranks escalation, escalation outranks allow, and anything no rule admits is refused.
policies/gate.policy.json escalate-scale-critical → require_approval when tier = critical and mutation = scale "A tier=critical workload carries capacity commitments an agent cannot see. Scaling it is a human decision." no-create-claiming-critical → deny when tier = critical, mutation = create, labels proposed "The object does not exist yet, so tier=critical is a claim by the order rather than a fact about a workload. An agent may not grant itself the tier that would exempt it from review." allow-known-mutations → allow when mutation is scale, restart, annotate or create "Scale, restart, annotate and create are the verbs this agent may use."
- Two enforcement points. The gateway's own policy file limits where it may write, and the cluster applies the service account's permissions on top. Loosen one and the other still refuses.
- Plain language, same gate. With plain language on, a model turns a sentence into one order. The model call is a record, the order cites it, and the gate decides exactly as it does for a typed order.
- A ledger that survives a restart. Every record is appended to a hash-chained ledger. A restart reads it back; an edited or dropped line is caught when it loads.
The limits, stated
- An escalation is not an approval. The pull-request path to a human is not built in this demo: an escalated order is recorded as needing approval, and nothing changes.
- Admission is not validation. The gate decides whether an order may proceed, not whether the workload will run well.
- The gate decides Deployments only. Other kinds are refused rather than applied ungoverned.
- One cluster, one demo namespace and one critical namespace owned by Argo CD. Not a production rollout.
The manifest comes from a public repository,
ok-admission-gate-demo, read without a
credential. The Decision Trace view is the published @agent-scope-ca/graph-canvas component.