Guardrails

Guardrails as code

Everything you set up in the UI you can also declare in the SDK — same profiles, same enforcement. A guardrail is a profile of plugin bindings, where each binding is one guardrail plus the action it takes. Synthesize it into a manifest and deploy it with the rest of your agent.

What you'll learn
  • The two ways to set up a guardrail — UI and SDK — and when to use each
  • How to declare a guardrail profile and attach it to an agent
  • How SDK actions map to Block / Re-ask / Auto-fix / Monitor
  • How to configure the PII scanner with the typed binding
  • What real shipping apps bind, and why

Two ways to set up a guardrail

A guardrail profile can be built either way — they produce the same runtime enforcement, so pick whichever fits how your team works. Many teams prototype in the UI, then move the final profile into the SDK so it ships and versions with the rest of the agent.

In the UIIn the SDK
Click through Guardrails → New Profile, pick a preset, toggle plugins, set each action, and attach it in the agent builder. See Create a guardrail.Declare a GuardrailProfile with pluginBindings and pass it to the agent — the rest of this page.

A guardrail profile in code

Install @dezifi/dak, create an App and Stack, then declare a GuardrailProfile and pass it to the agent's guardrail prop.
guardrails.ts
import {
  App, Stack, Agent,
  GuardrailProfile, GuardrailScope,
  GUARDRAIL_PLUGIN, GuardrailAction,
} from '@dezifi/dak';

const app = new App({ name: 'support-app' });
const stack = new Stack(app, 'Production', { workspace: 'acme-prod' });

const guardrails = new GuardrailProfile(stack, 'Guardrails', {
  profileName: 'support-bot-guardrails',
  scope: GuardrailScope.AGENT,
  pluginBindings: [
    { pluginId: GUARDRAIL_PLUGIN.PROMPT_INJECTION_DETECTION, action: GuardrailAction.EXCEPTION },
    { pluginId: GUARDRAIL_PLUGIN.PII_SCANNER,                action: GuardrailAction.FIX },
    { pluginId: GUARDRAIL_PLUGIN.TOXICITY_CLASSIFIER,        action: GuardrailAction.REASK },
  ],
});

new Agent(stack, 'Agent', {
  name: 'support-bot',
  // ...model, systemPrompt, tools...
  guardrail: guardrails,
});

app.synth();

Actions map to outcomes

Each binding's action is the outcome when that guardrail triggers — the same four outcomes the UI exposes:

SDK actionOutcomeWhat happens
EXCEPTIONBlockStops the turn; returns a safe canned message.
REASKRe-askRe-prompts the model for a graceful decline (one retry).
FIXAuto-fixCorrects the content (e.g. redacts PII) and continues.
NOOPMonitorLogs the match to the audit trail; passes through unchanged.

Plugin id reference

Bind plugins by their GUARDRAIL_PLUGIN constant so you never hand-type an id. Each runs at a fixed point in the turn.
GuardrailConstantRuns on
Prompt Injection DetectionPROMPT_INJECTION_DETECTIONInput
LLM Injection DetectorLLM_INJECTION_DETECTORInput
PII Scanner (Input)PII_SCANNER_INPUTInput
Topic RestrictionTOPIC_RESTRICTIONInput
Embedding Topic ClassifierEMBEDDING_TOPIC_CLASSIFIERInput
LLM Topic ClassifierLLM_TOPIC_CLASSIFIERInput
Toxicity ClassifierTOXICITY_CLASSIFIERInput
Image Content SafetyIMAGE_CONTENT_SAFETYInput + Output
PII ScannerPII_SCANNEROutput
Custom Regex PatternREGEX_PATTERNOutput
Grounding / HallucinationGROUNDING_CHECKOutput
Semantic GroundingSEMANTIC_GROUNDINGOutput
Reasoning AuditREASONING_AUDITExecution

Configure the PII scanner

The PII scanner has a typed helper — PiiScannerBinding — so you set categories and detection options without raw param strings. Use .input() to screen user messages and .output() to screen agent responses.
pii.ts
import {
  PiiScannerBinding, PiiCategory, CategoryPolicy, PiiEntityType, GuardrailAction,
} from '@dezifi/dak';

pluginBindings: [
  // Screen incoming user messages
  PiiScannerBinding.input({ enableNer: false }),

  // Screen agent responses
  PiiScannerBinding.output({
    action: GuardrailAction.FIX,
    enableNer: true,                 // also catch names / addresses in free text
    nerConfidenceThreshold: 0.6,
    nerEntityTypes: [PiiEntityType.PERSON_NAME, PiiEntityType.DATE_OF_BIRTH],
    categoryPolicies: [
      { category: PiiCategory.CONTACT,   policy: CategoryPolicy.ALLOW_USER_OWNED },
      { category: PiiCategory.FINANCIAL, policy: CategoryPolicy.ALWAYS_REDACT },
    ],
  }),
]

Real examples from shipping apps

Every profile below is copied from an app in production or the pattern library — different risk surfaces, different bindings.
  1. 1

    Customer support agent

    Redact any PII that leaks into a reply, de-escalate abusive input, and hard-block jailbreak attempts.

    customer-support.ts
    pluginBindings: [
      { pluginId: GUARDRAIL_PLUGIN.PII_SCANNER,                action: GuardrailAction.FIX },       // redact leaked PII
      { pluginId: GUARDRAIL_PLUGIN.TOXICITY_CLASSIFIER,        action: GuardrailAction.REASK },     // de-escalate abuse
      { pluginId: GUARDRAIL_PLUGIN.PROMPT_INJECTION_DETECTION, action: GuardrailAction.EXCEPTION }, // block jailbreaks
    ]
  2. 2

    RAG-grounded chatbot

    Keep answers grounded in the knowledge base — a semantic grounding check flags responses that stray from the retrieved source.

    rag-chatbot.ts
    pluginBindings: [
      { pluginId: GUARDRAIL_PLUGIN.PII_SCANNER,                action: GuardrailAction.FIX },
      {
        pluginId: GUARDRAIL_PLUGIN.SEMANTIC_GROUNDING,
        action: GuardrailAction.FIX,
        phases: [GuardrailPhase.OUTPUT],
        params: { threshold: 0.75 },
      },
      { pluginId: GUARDRAIL_PLUGIN.PROMPT_INJECTION_DETECTION, action: GuardrailAction.EXCEPTION },
    ]
  3. 3

    Incident responder

    An agent with production access: never leak a secret (hard-block on a match), and watch for the plan drifting away from the user's request.

    incident-responder.ts
    pluginBindings: [
      { pluginId: GUARDRAIL_PLUGIN.PII_SCANNER,    action: GuardrailAction.FIX },
      {
        pluginId: GUARDRAIL_PLUGIN.REGEX_PATTERN,
        action: GuardrailAction.EXCEPTION,
        params: { patterns: ['AKIA[0-9A-Z]{16}', 'xox[baprs]-[0-9A-Za-z-]+'] }, // AWS keys, Slack tokens
      },
      { pluginId: GUARDRAIL_PLUGIN.REASONING_AUDIT, action: GuardrailAction.NOOP }, // watch for goal drift
    ]
  4. 4

    Résumé screening (Java, EU AI Act)

    A shipping hiring app. A résumé is untrusted, PII-dense text: block injection on input, tokenize PII in and out, require the score to be grounded in the résumé, and audit the reasoning — the record-keeping and bias controls hiring AI needs. The Java SDK mirrors the TypeScript one.

    ResumeScreeningStack.java
    return new GuardrailProfile(stack, "ScreeningGuard", GuardrailProfileProps.builder()
        .profileName("screening-guard")
        .scope(GuardrailScope.AGENT)
        .pluginBindings(List.of(
            binding(GuardrailPlugin.PROMPT_INJECTION,   GuardrailPhase.INPUT,    GuardrailAction.EXCEPTION),
            binding(GuardrailPlugin.PII_SCANNER_INPUT,  GuardrailPhase.INPUT,    GuardrailAction.FIX),
            binding(GuardrailPlugin.PII_SCANNER,        GuardrailPhase.OUTPUT,   GuardrailAction.FIX),
            binding(GuardrailPlugin.SEMANTIC_GROUNDING, GuardrailPhase.OUTPUT,   GuardrailAction.REASK),
            binding(GuardrailPlugin.REASONING_AUDIT,    GuardrailPhase.PLANNING, GuardrailAction.NOOP)))
        .build());

Scope: workspace vs agent

Set scope to control where a profile applies: WORKSPACE is the baseline for every agent in the workspace, AGENT attaches to a single agent, and WORKFLOW scopes to one workflow. Because content-rewriting guardrails (PII, custom regex) change output for every agent, bind them at agent scope so each agent owns its own redaction.

scope.ts
import { GuardrailScope } from '@dezifi/dak';

new GuardrailProfile(stack, 'Baseline', {
  profileName: 'workspace-baseline',
  scope: GuardrailScope.WORKSPACE,   // default — applies to every agent
  pluginBindings: [ /* ... */ ],
});

Synthesize and deploy

app.synth() writes an AIformation manifest; the dak CLI provisions the profile alongside your agents. The profile only enforces once it is attached to an agent or workflow.

bash
dak deploy      # synthesizes the manifest and provisions it on Dezifi

Frequently asked questions

Should I set guardrails up in the UI or the SDK?
Either — they produce identical enforcement. Use the UI to explore and prototype; use the SDK when you want the profile versioned, reviewed, and deployed with the rest of your agent infrastructure. A common flow is to prototype in the UI, then codify the final profile in the SDK.
Do I need to list phases on every binding?
No. Each plugin has a default phase (input, output, or execution) and runs there automatically. Set phases only when a plugin supports several and you want to narrow it — e.g. pinning the semantic grounding check to OUTPUT.
What happens if I bind an unknown plugin id?
Synthesis fails with a validation error before anything deploys. Always bind via the GUARDRAIL_PLUGIN constants (or the Java GuardrailPlugin constants) so the id is checked at compile time.
Is the Java SDK a first-class option?
Yes. The Java and TypeScript SDKs expose the same resources and produce the same manifest. The résumé-screening example above is a real Java app. Pick whichever language your infrastructure code lives in.