Skip to main content

Author custom guardrail rules

The platform’s fixed scanners — prompt injection, PII detection, harmful content, blocked topics, sensitive words — cover the universal classes. They cannot express tenant-specific rules like “never mention competitor X”, “flag reservation codes that match a carrier format”, or “scrub internal SKU prefixes before the reply reaches the customer.” Custom guardrail rules close that gap. You author them as a JSON array in safety_config.custom_guardrail_rules, the same safety_config blob that already carries blocked_topics, sensitive_words, and locale_pii_patterns. Evaluation is deterministic: the same text and the same rules produce the same violations every time — there is no LLM, no clock, and no network in the matching path. That makes a custom rule reproducible in a unit test and identical in production. Custom rules are per-agent and separate from the central guardrail-policy presets you may also have attached. A rule you write here applies to this agent only. The endpoint paths below are relative. Send them against https://api.orbit.devotel.io/api/v1.

Rule shape

Each rule in custom_guardrail_rules is a JSON object: A fully annotated example:
Up to 25 rules per agent; each pattern up to 200 characters; each id and name up to 64 characters. Values outside those bounds are rejected at save time with a 422.

Semantics per action

  • block — raises a violation and hands the decision to the same severity reducer the fixed scanners use. A high or critical severity stops the turn (the caller gets a refusal); low or medium records the violation without stopping the turn. Use this for rules that must prevent a category of input or output.
  • redact — replaces every match in the text with the literal marker [REDACTED] before the turn proceeds, and emits a low-severity violation so the scrub is visible in the violation log. On output rules this happens before the reply is returned (or spoken on a voice agent); on input rules it scrubs the user message before the model sees it.
  • warn — records the violation at the severity you set, never blocks. Use this for observe-only rollouts: measure how often a rule would fire, then flip action from warn to block once you are satisfied.

Write path

Set custom_guardrail_rules on agent create or update, alongside the other safety_config fields:
Validation runs before the rules are persisted. A bad shape, an out-of-enum direction/match/action/severity, or a regex that does not compile returns a 422 VALIDATION_ERROR naming the rule index and field, for example custom_guardrail_rules[0].pattern is not a valid regex. Fix the rule and resubmit. Defense in depth: if a malformed rule ever reaches the runtime (for example, JSON written through a path that bypassed the API validator), that rule is skipped rather than throwing — a poisoned rule can never break an agent turn.

Evaluation order

Custom rules run at a defined point in each guardrail leg:
  • Input leg — after the prompt-injection scanner, PII detection, blocked topics, and the encoding checks, and before the passed decision. A contains rule sees the same post-unicode-cleanup text the fixed scanners see.
  • Output leg — after PII redaction, the content filter, and the citation check, and before the passed decision. A rule on output sees the post-redaction text, so a term a PII redactor already masked does not re-fire a custom rule.
On both legs the resulting violations fold into the normal pass/block reducer and the violation-log feed, alongside the violations the fixed scanners raise. Text length caps apply before evaluation: 50,000 characters on input, 100,000 on output.

Two worked rules

Never mention a competitor (observe, then block). Start in warn mode so you can measure how often the rule fires without disrupting turns:
Watch the violation feed in guardrail analytics. When the firing rate looks right, flip action to block and (optionally) severity to high so a mention stops the turn with a refusal instead of just logging. Redact internal SKU prefixes (output, regex). Internal prefixes such as SKU- followed by digits should never reach the customer:
Every occurrence is replaced with [REDACTED] before the reply is returned, and a low-severity violation records that the scrub fired. For a shape match like this, prefer regex over contains so you match the whole prefix-plus-digits form rather than a fixed literal.