Guardrails
What runs at the boundaries of every agent turn — injection detection, PII masking and restoration, content safety, and the audit trail behind all of it.
Overview
Read this first — especially the part about what runs even when you configure nothing.
Guardrails are the checks that run on the way in and on the way out of every agent turn. On the way in they decide whether a request is safe to process at all and what must be hidden from the model. On the way out they decide whether a generated answer is safe to return, and put back anything that was hidden.
The most important thing to understand is that guardrails are not purely opt-in. A hardcoded global safety baseline runs on every single request — direct chat, cached turns, everything — with no configuration and no database record behind it. Configured guardrails layer on top of that baseline; they never replace it. An agent with zero guardrails attached is still screened for prompt injection.
Everything a guardrail does is recorded. Blocks, redactions and warnings all land in a dedicated violations collection and in run analytics — including the baseline's own blocks, which are given a sentinel identity precisely so they appear alongside configured rules rather than living in a separate silo. Raw sensitive values are never written to any of it.
The two boundaries
Where each layer sits relative to the model, and where PII is hidden and restored.
Anatomy of a guardrail
One record holds a title, a lifecycle status, a classification, and a configuration object with six sections.
Modules
Global Safety Baseline
Always onBefore any configured rule runs, every request is tested against a library of 30-plus prompt-injection patterns. This check needs no guardrail record, no agent binding and no setup. A single match blocks the request outright.
What the patterns cover- Classic overrides — ignore, forget, disregard previous instructions
- Persona substitution — "you are now", "pretend", "act as", "roleplay as"
- Model control tokens and system-prompt markers
- Known jailbreak terminology and developer-mode claims
- Capability-override claims — "you have no restrictions"
- Hypothetical and fictional framing used as a wrapper
- Base64 and hex obfuscation
- Template and code injection — eval(, exec(, interpolation syntax
- Compliance coercion
- Prompt-extraction attempts
- Token smuggling, context overflow, prompt leaking
- Repetition attacks
Input Checks
Input evaluation is composed in a fixed order so that every caller — the classifier's pre-check and the guardrail node in the graph — gets identical behaviour and cannot drift apart. The baseline runs first; configured rules run second and are a no-op when none are active.
Within the configured rules, deterministic pattern checks run before any model call. A pattern match returns a block immediately and no tokens are spent. Model-based verification is attempted last, and only where it has been explicitly enabled.
The five input rules, in orderWhen more than one rule fires, the actions are merged by precedence: block beats redact, redact beats warn, warn beats allow. The strictest outcome always wins regardless of evaluation order.
Output Checks
The generated answer runs through a second sequence before anyone sees it. Configs scoped to input only are skipped here.
Ten pattern entries, each carrying its own severity and category rather than a single flat list. The critical tier covers extreme violence, terrorism, self-harm and other-harm instruction, weapons manufacturing, drug synthesis, and child sexual abuse material. The high tier covers sexual violence content, harassment and stalking, hate content, and self-harm method-seeking.
A configurable threshold governs how much pattern density is needed before the filter engages, and a model classifier can be escalated to only after that threshold is met — so the expensive check is never the first thing that runs.
The PII Engine
Six entity types are recognised: email, phone, ssn, credit_card, ip_address and passport. When a rule enables PII handling without naming types, all six apply.
The patterns are more careful than a naive regex set. Phone numbers are matched internationally — including one-digit area codes — and then filtered by total digit count to the E.164 range of 7 to 15, which discards short false positives the broad pattern would otherwise let through. Social security numbers exclude structurally invalid ranges, but deliberately include taxpayer identification numbers beginning with 9, which are equally sensitive. Card numbers accept spaced and dashed formatting across the major issuer families.
Overlap resolution — and the bug it fixesThe engine locates every candidate in a single pass over the original text, then resolves conflicts: on a clash the longest match wins, and an earlier start breaks ties so the scan stays deterministic and left-to-right.
Masking is only half the design. Each distinct value is allocated its own indexed placeholder — [EMAIL REDACTED] becomes [EMAIL_REDACTED_3] — so restoration is an exact lookup rather than positional guesswork. The placeholder is deliberately shaped with no spaces and in a form that matches none of the PII patterns itself, so it survives a second masking pass untouched.
One placeholder per value also means the model sees one stable identity for one real person across a turn — the same email always becomes the same token, which keeps the text coherent instead of reading as several different people.
Content Safety
Four harm categories can each be given their own block threshold: hate_speech, harassment, sexual_content and dangerous_content. Detected severity is rated none, low, medium or high, and the threshold names the minimum severity that triggers a block.
Enforcement is two-tier and ordered for cost. A deterministic base check runs first against your own blocklist — there is no built-in word list, only terms you supply — along with exact and suffix domain blocking. The model-based harm classifier is escalated to only if the base check did not already block, so the expensive path is skipped whenever the cheap one has already decided.
The classifier prompt describes each category in neutral terms, and the source deliberately contains no explicit examples.
Fail-open versus fail-closedThis distinction matters more than any single rule, and the two model-based checks behave differently on purpose:
Violations & Audit
Every block, redaction and warning is written to a dedicated violations collection. Records carry the session, user and agent, the guardrail identity and title, the rule type, severity, action, direction, a detail string, and whether the request was actually blocked.
- Indexed by session, user, agent and guardrail
- Compound index for session history, newest first
- Compound index for per-guardrail history
- Compound index for blocked events per agent
- Unordered bulk insert so one bad record cannot drop the batch
- Write failures are rethrown, never swallowed
Each run also records a per-direction summary alongside its token and cost figures — whether guardrails were evaluated at all, the outcome as passed, warn, modified, blocked or skipped, which check caused a block, and the rule types that fired with their severity and action. No content appears in analytics — only rule types.
Safety-check token spend is tracked per direction too, so the cost of running guardrails is visible separately from the cost of the answer itself.
How Guardrails Work — Flow Examples
Four diagrams. Severity labels beside each rule are the values actually recorded when that rule fires.
Example 1 — The input path Input
The baseline first, then five configured rules in fixed order, then masking. Pattern checks resolve before any model call, so a blocked request costs no tokens.
Example 2 — The output path Output
Six rules on the way back, ending with restoration so the user sees real values that the model never held.
Example 3 — Overlap resolution in PII masking PII
Why candidates are collected first and resolved second. Running one regex per type over the previous result let adjacent values clip each other.
Example 4 — Where a violation goes Audit
Three destinations, none of which ever receives a raw sensitive value.
Reference Tables
Rules with the severity each records, the PII entity set, and the safety thresholds.
Rules by direction
| Rule type | Severity | Default action | Model call |
|---|---|---|---|
| Always on | |||
| global_safety | critical | block | No |
| url_safety | high | block | Classifier stage |
| Input | |||
| max_input_length | medium | block | No |
| prompt_injection | critical | block | Optional, after a pattern hit |
| blocked_topic | high | block | Optional semantic check |
| pii_in_input | high | warn | No |
| language_filter | low | warn | No |
| Output | |||
| max_output_length | low truncate / medium block | configurable | No |
| pii_in_output | high | redact | No |
| toxicity | critical | block or redact | Optional escalation |
| topic_adherence | medium | block | Optional semantic judge |
| format | low | warn, block in strict mode | No |
| confidence_disclaimer | low | append | No |
PII entity types
| Type | Detection notes |
|---|---|
| Standard address form | |
| phone | International and domestic forms, filtered to a 7–15 digit E.164 range to drop short false positives |
| ssn | Excludes structurally invalid ranges; taxpayer identification numbers beginning with 9 are deliberately included |
| credit_card | Major issuer families, with optional spaces or dashes between groups |
| ip_address | Dotted-quad IPv4 with octet range validation |
| passport | One or two letters followed by six to nine digits |
Content-safety thresholds
| Threshold | Effect |
|---|---|
| BLOCK_NONE_AND_ABOVE | Category disabled — nothing is blocked |
| BLOCK_LOW_AND_ABOVE | Blocks at detected severity low, medium or high |
| BLOCK_MEDIUM_AND_ABOVE | Blocks at detected severity medium or high |
| BLOCK_HIGH_AND_ABOVE | Blocks only at detected severity high |