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

Python · 10 lines
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

Python · 3 lines
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:

Python · 4 lines
from zerda.prompt import GuardrailEngine

custom_engine = GuardrailEngine(extra_guardrails=[no_legal_advice])
engine = PromptEngine(guardrail_engine=custom_engine)

3. Verify it's applied

Python · 2 lines
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.

Related pages