# Policy as Code for AI Agent Enforcement: What It Means

> Markdown mirror for AI agents, generated 2026-08-12 from the live page.
> Canonical: https://agenticrail.nz/blog/policy-as-code-ai-agent-enforcement/
> Site context: https://agenticrail.nz/llms.txt

[AgenticRail](https://agenticrail.nz/) › [Writing](https://agenticrail.nz/blog/) › Policy as Code — AI Agent Enforcement

 Governance 2026-05-12 · reviewed 2026-07-21 Kade Cowper

# Policy as Code for AI Agent Enforcement: What It Means and How It Works

Policy as code is arriving in AI agent governance, and most of what is being published about it describes declaration: expressing agent policy as structured configuration rather than prose. The part most implementations leave out is enforcement: a runtime gate that evaluates the policy against every action before execution and produces a signed receipt as proof.

## Why Can't AI Agent Policy Just Live in the System Prompt?

Most AI agent "policies" today live in the system prompt. The prompt tells the agent what it's allowed to do, what steps to follow, what data it may access. This is policy-as-natural-language: readable by humans, interpretable by the model, unenforceable by anything.

A system prompt is a probabilistic instruction. The model reads it and approximates compliance on each generation. There is no mechanism that prevents a non-compliant action from executing — if the model generates a bad output, the action runs. If a prompt injection overwrites the instruction, the agent follows the injection. If the model simply hallucinates a step that isn't in the policy, nothing stops it.

 | Policy expression | Machine-readable | Versioned | Enforced before execution | Auditable evidence |
 | System prompt / guidelines | No — natural language | No — lives in model context | No — probabilistic | No — model output only |
 | Post-hoc evaluation (LLM judge) | Partial — structured prompt | Partial — prompt versioning | No — runs after execution | Partial — evaluation records |
 | Policy as code — enforcement gate | Yes — structured contract | Yes — versioned with deployment | Yes — gate fires pre-execution | Yes — signed receipt per decision |

## What Is Policy as Code for AI Agents?

Policy as code in the DevOps sense (Open Policy Agent, HashiCorp Sentinel) evaluates infrastructure configuration at deploy time — checking whether a proposed change conforms to policy before it is applied. That is useful, but it is a one-shot check at a single point in a deployment pipeline.

Agent policy as code is a continuous runtime check. The policy is evaluated on every action, during a live session, in the critical window between the agent's decision to act and the action's execution. The enforcement point is not "before deploy" but "before each tool call."

Three components are required:

1 — Step Order Contract

- Declares the permitted sequence of steps
- Machine-readable string or config
- Versioned with the enforcement worker
- Violations → SEQUENCE_VIOLATION

2 — Action Type Map

- Declares which action categories each function permits
- Versioned policy map (not prompt instructions)
- Violations → ACTION_NOT_ALLOWED
- Steps outside the declared order → UNKNOWN_STEP

3 — Enforcement Gate

- Independent of the agent — cannot be overridden
- Evaluates policy before execution
- Returns ALLOW or DENY
- Writes signed receipt at decision time

The policy is not "what the agent believes it should do." The policy is what the gate evaluates against. The agent's understanding is irrelevant — the gate's decision is authoritative.

## How Do You Enforce Step Order in an AI Agent Before It Executes?

AgenticRail implements policy as code as a two-part contract: the step order and the function/action_type map.

**The step order** is declared as an ordered list. For an 8-step MSMD spine:

Step order policy — versioned environment variable

```
SLP8_STEP_ORDER_MSMD="intake,disruption,instability,state_read,internal_driver,execution,boundary,settle"
```

This string is the policy. It is stored as an environment variable on the enforcement worker, deployed as part of the worker version, and auditable via the deployment history. Every receipt written by the gate carries the policy identifiers in effect at decision time (`policy_map_ids`, in the receipt metadata) alongside the signing key identifier (`key_id`) — the policy version is stamped into the receipt that proves it ran.

**The function/action_type map** declares which action categories each function permits:

Policy map — function → permitted action types

```
// an illustrative domain policy — your map, your action types
"intake": ["CHECK_STATE", "READ_INPUT"]
"execution": ["WRITE_DB", "CALL_EXTERNAL_API"]
"settle": ["SEAL_SEQUENCE"]
```

An agent attempting to call `WRITE_DB` during `intake` — regardless of what its prompt or reasoning said was appropriate — receives `DENY: ACTION_NOT_ALLOWED` before the write executes.

AgenticRail's own production policy for the MSMD spine carries a sharper rule worth copying: the `execution` step (the doer) permits only `SELECT_NEXT_STEP` and `PAUSE_CYCLE` — it cannot record its own results. Witnessing happens at the following step (`boundary`), and a result recorded there must carry a verifiable link to the receipt of the work it attests to, or it is denied (`ARTIFACT_UNBOUND`). The doer cannot self-attest; that separation is policy, enforced.

## What Actually Stops a Non-Compliant Agent Action From Running?

The gate is what separates policy-as-code from policy-as-documentation. Without a gate, you have a policy document. With a gate, you have enforcement.

The gate sits between the agent and every downstream action. The agent does not call tools directly — it calls the gate, which evaluates the declared policy and decides whether the action may proceed. The agent cannot route around the gate; it cannot modify the policy at runtime; it cannot bypass the nonce check or the step order constraint.

Key property

The agent is the regulated system. The gate is the regulator. A system cannot regulate itself — the independence of the gate is what makes the policy enforceable rather than advisory.

Every gate decision produces a signed receipt, written before the action executes:

ALLOW receipt — policy check passed, action authorised

```
{
 "pack_id": "24449424694a3f...e020", // SHA-256, 64 hex
 "decision": "ALLOW",
 "reasons": [],
 "executed": true, // permitted — not proof the downstream action performed
 "meta": {
 "model_id": "client:acme-bank",
 "sequence_id": "loan-approval-20260512-001",
 "step": "execution",
 "function": "execution",
 "action_type": "SELECT_NEXT_STEP",
 "policy_map_ids": ["msmd_policy_v1"]
 },
 "payload_hash": "9080bd2ac4da...86cb",
 "prev_receipt_hash": "b6a18d234e38...338d",
 "ts_ms": 1715508000000,
 "key_id": "k2_2026-06-07_ed25519",
 "signature_alg": "Ed25519",
 "signature": "TpQr8f3aXz9c2b1d..." // base64, over the canonical receipt
}
```

## What Happens When an AI Agent Action Violates Policy?

When the policy is violated, the gate returns a specific reason code. Each code maps to a distinct policy rule:

SEQUENCE_VIOLATION

Step submitted out of declared order. Step order policy enforced.

ACTION_NOT_ALLOWED

Action type not in the permitted set for this function.

UNKNOWN_STEP

Step/function not present in this sequence's own declared step order.

REPLAY_NONCE

Nonce already used in this session. Replay protection policy enforced.

SEALED_SEQUENCE

Session reached final step and was sealed. No further actions permitted.

STALE_TIMESTAMP

Request timestamp outside the 5-minute freshness window.

FUNCTION_STEP_MISMATCH

Step and function fields disagree. The contract requires step === function.

ARTIFACT_UNBOUND

A result recorded at the witnessing step without a verifiable link to the receipt of the work it claims. The doer cannot self-attest.

Each denial produces a signed receipt — tamper-evident, pre-execution evidence that the policy ran and what it rejected. These receipts are the operational exhibits that compliance auditors, EU AI Act documentation, and ISO 42001 evidence packages cite.

## How Is AI Agent Policy Versioned and Audited?

Because the policy is expressed as code — not embedded in a prompt — it has all the properties of code:

- **Versionable:** every policy change is a deployment. The git history and worker deployment log are the policy audit trail.
- **Diffable:** you can compare two policy versions and see exactly what changed — which steps were added, which action types were permitted or revoked.
- **Attributable:** each receipt references the key_id of the signing key active at decision time. An auditor reviewing receipts from any session can determine which policy version was in effect for each decision.
- **Testable:** the policy can be tested in isolation from the agent. Submit a sequence with a deliberate SEQUENCE_VIOLATION — the gate must return DENY. The policy is verifiable independently of the model that calls it.

 8 Specific DENY reason codes

 Pre-exec Receipt written before action runs

 Versioned Policy stamped into every receipt

## Does Policy as Code Satisfy EU AI Act, ISO 42001, or NIST AI RMF Compliance?

 | Framework | Requirement | What policy as code evidences |
 | EU AI Act Article 9 | Risk management system — identify, analyse, mitigate risks | The declared risk boundary plus proof it was enforced — the evidenced core of a risk management system, not the whole system |
 | EU AI Act Article 12 | Automatic logging enabling reconstruction of events | Pre-execution receipts are the reconstruction anchors — not post-hoc observations |
 | ISO/IEC 42001 A.6.1.6 | Controls for AI system operation — documented and evidenced | Policy document + receipt chain = documented control + evidence it ran |
 | NIST AI RMF Manage 2.4 | Accountability mechanisms for AI system decisions | Every gate decision attributed to a policy version, signed, and stored tamper-evidently |
 | OWASP ASI01 (Goal Hijack) | Prevent agent from being redirected to unauthorised objectives | Step order and action type policy enforced externally — prompt injection cannot override the gate’s evaluation |

## Why Do Most "Policy as Code" Implementations Still Not Enforce Anything?

The industry conversation about policy as code for AI agents tends to stop at declaration. Expressing agent governance as structured configuration rather than prose is valuable — it is readable by tools, comparable across versions, and unambiguous in intent.

But declaration without enforcement is documentation. A policy document does not prevent a non-compliant action from executing. It describes what should happen; it does not guarantee what does happen.

The enforcement gate is what makes the code operative. Without it, "policy as code" is a better way of writing the same unenforceable guidelines that used to live in the system prompt.

### See policy as code in action

Run a sequence through the AgenticRail gate — submit a step out of order and inspect the SEQUENCE_VIOLATION receipt. [Open Demo](https://agenticrail.nz/demo/) [Read Docs](https://agenticrail.nz/docs/) [← All posts](https://agenticrail.nz/blog/)
