Policy-as-code for enterprise agent governance
Enterprises say yes to agents when policy is executable at runtime. This reference build turns governance from a document beside the system into a versioned decision surface: every action is evaluated, high-risk work pauses for named approval, hard boundaries deny explicitly, and the evidence preserves which policy made the decision.
The problem
Agent governance often begins as a review document: approved tools, forbidden actions, escalation guidance, and a list of principles. The document may be sensible and still be operationally irrelevant. If the runtime cannot evaluate the request against it before an effect occurs, the policy is advice, not control.
The opposite failure is a generic permission check. “The agent has access to the API” collapses action, resource, risk, environment, authority, and policy version into one yes/no decision. That is too coarse for enterprise work. A read in a sandbox, a production export, and a high-risk customer update should not share the same approval semantics.
The constraints
The build has to remain deterministic and inspectable. A request must identify an actor, action, resource, and attributes. A policy must be versioned, rules must have stable identities, and the result must say whether execution is allowed, approval is required, or the action is denied. Deny must win over approval so a broad human approval cannot bypass a hard boundary.
The evaluator also has to be useful without pretending to be a complete IAM system. This is a local reference build: it proves the decision and evidence contract, while identity verification, signed policy distribution, distributed consistency, and authorization-token issuance remain explicit deployment concerns.
The decisions
Policy is a versioned artifact. Rules live in a declarative JSON policy bundle with stable IDs, effects, actions, conditions, and reasons. Incrementing the policy version is a visible governance change, not an invisible configuration edit.
Approval is a typed outcome. A high-risk update returns approval_required with a concrete scope such as update_customer:customer/7. A named approver can satisfy that exact gate; “a human looked at it” is not a substitute for scoped authority.
Deny precedence is non-negotiable. An explicit production export prohibition remains denied even when an approval payload is supplied. This prevents generic approval workflows from eroding the boundary that policy intended to enforce.
Audit evidence is part of enforcement. Every evaluation records actor, action, resource, policy version, matched rules, decision, and reason in an append-only JSONL ledger. The evidence makes a policy decision reconstructable rather than merely observable as a final outcome.
The outcome
The build demonstrates a control surface that can answer: what did the agent ask to do, which rules matched, who was required to approve it, why was it denied, and which policy version was active. The evaluator is deterministic, the approval boundary is explicit, and the deny path cannot be overridden by a generic approval record.
The honest caveat: this is a reference build, not a production authorization service. It has no claims about throughput, identity assurance, cryptographic signing, distributed policy storage, or multi-tenant isolation. It proves the runtime policy contract and evidence shape that a deployed control plane would need to harden.
What is implemented
The repository is structured as a small Python package with a declarative policy fixture, evaluator, enforcement API, JSONL audit writer, five behavioral tests, and four self-checking scenario scripts. It runs without a model, API key, database server, or external policy engine.
cd ~/Code/agent-policy-as-code
uv sync --extra dev
uv run pytest -q
uv run python -m agent_policy.demo
for s in scripts/scenario_*.py; do uv run python "$s"; done
The current local repository is ready to be checked into the Dhristhi GitHub organization. A public repository link will be added here after check-in.