What no one combines — and what we learned.
Each load-bearing property exists somewhere in the OSS landscape. Runelm is the first library to combine all five into one enforced pipeline — fail-closed by default. Here is the honest read on the field.
Five properties. Six libraries. Zero overlap.
Each load-bearing property exists somewhere in the landscape. Runelm is the first library to combine all five into a single enforced pipeline — fail-closed by default.
| Property | Runelm | NeMo | Guardrails AI | Presidio | LLM Guard | Lakera | PromptGuard |
|---|---|---|---|---|---|---|---|
Classification tiers drive routing BLOCKED / HIGH / MEDIUM / LOW determine which provider is reachable, not just a risk score. | ✓ Four tiers, each pinned to a provider tier registry. Operators cannot override. | ◐ | ✗ | ✗ | ✗ | ◐ | ◐ |
Deterministic, session-scoped, type-preserving pseudonyms Acme Corp is always the same rune within a session, in a format that preserves the entity's syntactic role. | ✓ Per-session counter, AES-256-GCM-encrypted map, runic stable placeholder. | ✗ | ✗ | ◐ | ◐ | ✗ | ✗ |
Routing enforcement keyed to classification HIGH stays L1 local. MEDIUM allowed only on contracted L2 with DPA. LOW can reach L3 pay-per-token. | ✓ There is no --allow-l3-for-high flag. The system does not ask. | ✗ | ✗ | ✗ | ✗ | ◐ | ◐ |
Map-bounded rehydration (anti-injection) Only reverse placeholders the outbound substitution map created. Synthesized placeholders in the response stay masked. | ✓ Defeats placeholder-synthesis exfiltration via prompt injection. | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
HMAC-hashed audit without prompt text Plain SHA-256 creates a confirmation oracle. HMAC with a server-side secret breaks it. | ✓ HMAC-SHA-256, tamper-evident store, audit-on-audit. | ✗ | ✗ | ✗ | ✗ | ◐ | ◐ |
Fail-closed by default Any error in classification, pseudonymization, routing, or audit blocks the request. Cleartext fallback is impossible. | ✓ The architectural invariant. Not a configuration flag. | ✗ | ✗ | ✗ | ✗ | ✗ | ◐ |
The libraries, one paragraph each
NVIDIA NeMo Guardrails
Apache 2.0Programmable input/output/dialog/retrieval rails authored in the Colang DSL.
what it does wellStrong on rail composition and self-check loops. The PII recognizer integrates Presidio but is bolt-on, not load-bearing.
what it misses for a DSPFail-open by default. No routing enforcement keyed to classification. Colang is one more language to learn for teams that just want a sanitization gate.
Guardrails AI
Apache 2.0Validators composed into a Guard. RAIL spec, Pydantic-typed structured outputs, retry/reask loops.
what it does wellBest-in-class at structured-output validation and JSON-schema enforcement.
what it misses for a DSPOnFailAction.NOOP exists and is sometimes a default — silent-continue is the wrong default for a security gate. No multi-tier routing. No deterministic session-scoped pseudonymization.
Microsoft Presidio
MITPluggable PII detection plus anonymization SDK. Analyzer + Anonymizer + Image Redactor.
what it does wellThe canonical PII detection toolkit. The Encrypt/Decrypt operator pair is the closest existing OSS primitive to reversible pseudonymization.
what it misses for a DSPNot a guardrail. No gate concept, no session scope, no routing. Runelm uses Presidio underneath for NER (stage 6 of the pipeline).
LLM Guard (ProtectAI)
MITFifteen input scanners + twenty output scanners. The closest existing tool to a DSP.
what it does wellAnonymize + Vault + Deanonymize triple is the only OSS pattern that does detect-pseudonymize-rehydrate in a single library.
what it misses for a DSPVault is process-global — cross-tenant leak waiting to happen. No map-bounded rehydration. No classification tier driving routing. No HMAC audit. Fail-soft default.
Lakera Guard
Proprietary (Check Point)Closed SaaS firewall — single POST /v2/guard endpoint. Sub-50ms, 100+ languages.
what it does wellExcellent shape for an external policy API.
what it misses for a DSPCannot self-host. A non-starter for sovereignty cases (EU AI Act high-risk, classified, defense, regulated finance).
PromptGuard (via LiteLLM)
MixedSelf-hostable AI security gateway. Three decision paths: allow / block / redact.
what it does wellThe most fail-closed-by-config in the lineup — block_on_error=true makes failure mode explicit.
what it misses for a DSPPseudonymization is redact-only. No session-scoped map, no map-bounded rehydration, no classification-driven routing.
What we learned from
- ᛟLLM Guard's scanner API ergonomics — (sanitized_text, is_valid, risk_score) is a clean uniform return contract.
- ᛟPresidio's recognizer registry — pluggable add_recognizer() is the right extensibility model.
- ᛟPresidio's Encrypt/Decrypt operator pair — AES-CBC reversibility is the right primitive.
- ᛟNeMo's separation of detect vs decide — keep the policy DSL separate from the recognizer code.
- ᛟPromptGuard's block_on_error=true — make it the default in Runelm.
- ᛟGuardrails AI's standalone-server mode — proves "swap your OpenAI base_url" works as an install pattern.
What we deliberately did not copy
- ᚲNeMo's Colang DSL — one more language, non-trivial parser. YAML + Pydantic instead.
- ᚲLLM Guard's process-global Vault — shared mutable singleton is wrong by default. Sessions own their own map.
- ᚲRebuff's "100% protection not possible" framing — technically true, bad security posture as a tagline.
- ᚲGuardrails AI's OnFailAction.NOOP — never make "silently continue" a default.
- ᚲPer-call LLM judges as the primary classifier — GPT-5 safety classifier adds 5-11s per check. Use small local models or rule+regex for the hot path.
- ᚲLakera's closed-API model — self-hostable or nothing.