Tutorial: Adding a Custom Guardrail
On this page
zerda.prompt ships 12 built-in guardrails (see GuardrailLibrary), but you'll often need domain-specific instructions — e.g. "never give legal advice" or "always ask for a case number before troubleshooting."
1. Define the guardrail
from zerda.prompt import Guardrail
no_legal_advice = Guardrail(
name="no_legal_advice",
instruction=(
"Do not provide legal advice or interpret contract clauses as binding legal counsel. "
"Recommend the user consult a licensed attorney for anything with legal implications."
),
priority=85, # between CITE_SOURCES (80) and NO_FABRICATION (95)
)
Priority determines render order — higher renders first in the numbered instruction list. See the full priority table in api/guardrails.
2. Attach it to the engine
from zerda.prompt import PromptEngine
engine = PromptEngine(extra_guardrails=[no_legal_advice])
extra_guardrails passed to PromptEngine are only used to build its default GuardrailEngine — if you also pass an explicit guardrail_engine=, extra_guardrails is ignored (see api/prompt_engine). To attach extras to a custom engine, pass them directly:
from zerda.prompt import GuardrailEngine
custom_engine = GuardrailEngine(extra_guardrails=[no_legal_advice])
engine = PromptEngine(guardrail_engine=custom_engine)
3. Verify it's applied
prompt = engine.build(query="Can I terminate this contract early?", documents=contract_docs)
assert "no_legal_advice" in prompt.guardrails_applied
Important: extras always apply
Custom guardrails added via extra_guardrails are appended after rule-based selection in GuardrailEngine.build(), regardless of request.enable_guardrails. There is no per-request way to suppress a specific extra guardrail — if you need conditional application, encode the condition into a wrapper you control before calling build(), e.g. by maintaining two PromptEngine instances with different extra_guardrails.
Localizing a custom guardrail
Built-in guardrails have natively-authored Arabic text (see api/templates.md). Custom guardrails do not — guardrail_text() will fall back to your Guardrail.instruction string verbatim regardless of request.language, since GUARDRAIL_TEXT in templates.py only has entries for the 12 built-in names. If you need a bilingual custom guardrail, branch on request.language yourself before constructing the Guardrail, or maintain two Guardrail instances and select between them at call time.