Runtime enforcement and evidence for AI governance
The AI enforcement layer.
Every model, tool and agent call is checked against your policy in line. Every decision leaves a signed record you can prove to anyone.
Source-available. Self-host in minutes. No account.
Measured on an Apple M4 over loopback. How, and what it means
What this is
An enforcement layer is the process between an application and a model that can refuse a call, change what it carries, and prove what it did.
- On the pathIt holds the connection rather than watching a copy of it, so a rule refuses a request instead of flagging it afterwards.
- Every call kindA model request, an MCP tool call and a message to a peer agent arrive at the same door, under the same keys, rules, budgets, guardrails and record.
- Decided per requestWhat reaches the model is assembled at runtime, so the decision is made at the moment the request is, not at a review before it.
- Evidence on your sideEach decision is signed by the node that made it and chained to the one before, in a store you hold, and the check runs without trusting that store.
Measured
314of 315
Change the language, change the verdict.
315 red-team prompts, annotated into ten languages by the paper's own annotators. One meaning per row, so the right answer is the same answer ten times. A widely deployed open guard model gives a different one on 314 of them.
It flags none of the English, 12% of the Italian, 76% of the Arabic and 98% of the Bengali. German, on a set of its own, fires on none of 27. Nothing visible from outside the model says which of your languages is which.
pistra guardrails eval scores any ONNX checkpoint you pin against your own annotated data, through the same inspection a request goes through. A profile then chooses which checkpoint inspects which traffic.
Access
Every model, tool and agent behind one door.
Teams get keys, budgets and the models they are allowed. MCP servers and peer agents sit behind the same door as the models, and clients find them through it: pistra serves the registry, and every connect URL in it is pistra's own address.
The SDKs they already use change one line. Nothing else in the client moves.
- Virtual keys with a profile. What a key may call, and how much, decided once per team.
- Budgets that stop. Tokens or cost, reserved before the call and settled after it.
- Every provider, one dialect. OpenAI, Anthropic, Gemini, Bedrock, vLLM and the rest, translated in place.
- MCP, governed. Tool calls policed at the hop, and a private registry on the official v0.1 API, so a registry-aware host needs one base URL.
- Peer agents, fronted. An A2A agent answers at pistra's address, with its card projected there and signed, so a peer can check the card it discovered is the card you served.
pistra_…9f2Asupport62% of 2M tok / dayactivepistra_…Tt09ci-bots8% of 500k tok / dayactivepistra_…Pq77finance97% of 1M tok / daynear cappistra_…7b01agents0% of 250k tok / dayrevokedEnforce
Nothing leaves that shouldn't.
Card numbers, identifiers and secrets are found in the stream and rewritten before the provider sees them, and turned back for the tools you trust. A refusal names its rule, and says why.
Redact PII from model output- Redaction in the stream, on the way in and the way out, without buffering the response.
- Format-preserving. A replaced card is still a valid card, so what is downstream keeps working.
- Rules in CEL on the key, the model, the tool and what the detectors found.
- Slow detectors without the latency. Run a model-backed check beside the stream, enforce from the next turn.
- Detectors measured, not assumed. The reports say which models we rejected, and what each one costs in the languages you serve.
Please cancel my card 4095260993934932, my id is 1044880134, and mail me at aarav@example.com.
Please cancel my card 6880989289285872, my id is <SA_NATIONAL_ID_1>, and mail me at <EMAIL_ADDRESS_1>.
the card is still sixteen digits and still passes Luhn, reversible only by this gateway
sa-ndmo-personal-data-abroad-needs-approval guardrail ruleProve
Evidence, not a claim.
Every decision is a signed, chained record that names the rule and the control it stood for. Your governance platform writes the policy it wants enforced, and reads the decisions back.
a41c…f07d08…3be92a…c7witnessed"event": "guardrail.decision", "outcome": "redacted", "actor": {"kind": "virtual_key", "name": "support-bot"}, "rule": "cards", "controls": ["pci-dss:3.4", "acme:DP-02"], "sig": "ed25519:node-0 …"
$ pistra audit verify -heads heads.json export.jsonl- A per-node hash chain, signed with a key the collector never holds; the cluster witnesses the heads.
controlson every rule. Your framework's identifiers, carried onto each decision the rule makes.- Never the content. The record says what was decided, not what was said.
pistra audit verifyreports anything altered, removed, moved, forged or cut short.
Deploy
Runs where you run.
Keys, budgets and certificates live in the binary's own raft log, so there is no Postgres and no Redis to run, back up or make highly available. Three replicas are the cluster.
The front door on Kubernetes
A Helm chart, its own TLS and a raft-backed cluster. Scale it like a StatefulSet.
pistra -config config.yamlOne binary on VMs
A binary and a config file. Keys, budgets and secrets live in its own raft log.
Beside the gateway you have
Inspect and enforce on traffic you don't route: no keys, no migration.
Run it yourself. Today.
One chart or one container, and the configuration reference for everything after that.
$ helm install pistra oci://ghcr.io/pistra-dev/pistra/charts/pistra
$ docker run ghcr.io/pistra-dev/pistra -upstream https://api.openai.com