Search

↑↓ to move↵ to openesc to closetop 6 documentation results

Book a demoTry TokenTriage

In development · Explore the product preview. Join the launch list or book a walkthrough.

Browse docs

Configuring a guard

The binding schema in full — id, category, phases, detectors, mode, thresholds, severity bands, and error handling.

How-to guideLast updated

On this page

A binding is one guard: a category, some detectors, the phases to run them on, and what to do when a finding clears the gate.

guardrails:
  enabled: true
  default_profile: standard      # applied to anonymous/keyless traffic; "" ⇒ off
  local_budget_ms: 50            # cumulative request budget for embedded detector work
  guards:
    - id: pii_in
      category: pii
      phases: [input]
      detectors: [pii.card, pii.email, pii.ssn]
      mode: monitor              # enforce | monitor
      threshold: 0.5             # minimum gate number a finding must clear
      severity_bands:
        - { min: 0.5, severity: low }
        - { min: 0.9, severity: high }
      ladder:
        low: observe
        high: redact
      on_error: open             # open | closed
      rule_ref: POL-PII-1
  profiles:
    standard: [pii_in]
How one guardrail binding resolves, from detectors to effectA binding names a category, a set of detectors and the phases to run them on. Each finding carries a score; the threshold decides whether it is considered at all, and the severity bands decide which rung of the ladder it lands on. The rung names a verb, such as redact. What the row records is not the verb but the effect — what actually happened to the bytes. The same redact verb records mutated when it spliced bytes in enforce mode, annotated in monitor mode where nothing is changed. A stock binding asking a spanless classifier to mutate is rejected during activation; it does not become a successful redaction.bindingcategory: piidetectors: [pii.card, …]phases: [input]mode: monitor | enforcegatesthresholdseverity_bandsa finding's score → a severityladderlow → observehigh → redactaction: is one-rung sugar for asingle-rung ladder at lowVERBredactwhat you asked foreffect: mutatedenforce, and the span was splicedeffect: annotatedmonitor — nothing was changedactivation refusedspanless detector + mutationthe verb is not the effecteffects require executionreversible on the row is DERIVED from the action table, never authored —redact stays irreversible even on a row whose effect is annotated.

The fields

Field What it does
id the binding’s name. It is what engaged[], fired[] and suspended[] carry, and what you alert on
category one of pii secrets injection toxicity topical code multimodal format custom. Every detector must belong to it
phases input · output · stream. Refused at boot if a named detector does not declare the phase
detectors the detector ids to arm. An unregistered id fails the compile
mode enforce or monitor. monitor runs and discloses and changes no byte
action one-rung sugar for ladder: {low: <verb>}
ladder the real severity → verb table. Use it when you want different verbs at different scores
threshold the minimum score a finding must clear before the ladder is consulted at all
severity_bands the score cut-points that decide which rung a finding lands on
on_error open (allow and disclose — the default) or closed (refuse unreleased traffic in enforcing mode); monitor preserves traffic
rule_ref your auditable policy pointer. It rides every fire on the row
local_budget_ms engine-level: the cumulative request budget for embedded detector work
stream_fallback monitor (default) or acknowledged closed for missing stream coverage; buffer is recognized syntax but refused by stock gateway activation
profiles / default_profile named sets of binding ids; the default applies to anonymous traffic. "" means off

action or ladder, not both jobs

action: redact is exactly ladder: {low: redact}. With no severity_bands configured, every finding lands at low — which is why the sugar works and why a one-rung binding needs neither bands nor a threshold. Reach for ladder when you want a real table:

      severity_bands:
        - { min: 0.5, severity: low }
        - { min: 0.8, severity: high }
      ladder:
        low: observe        # note it and move on
        high: redact        # splice it out

mode: simulate is not a thing

      mode: simulate     # ✗ refused by validation

binding "pii_in": mode 'simulate' is the off-path simulate API's stamp, never a configured mode

Simulation is a property of a dry-run report, not of a policy. The dry run lives at tokentriage guardrails test and POST /tt/api/v1/guardrails/simulate; see Proving it before you arm it.

The two settings that make you type out a consequence

on_error: closed requires fail_closed_ack

on_error decides what happens when inspection cannot complete. Under enforce, open allows traffic with a failure receipt; acknowledged closed refuses input or suppresses unreleased output. Monitor mode preserves traffic and discloses the failure under either posture. See the failure matrix.

      on_error: closed
      fail_closed_ack: "outage-over-leak, signed off by platform-security 2026-08-07"

Without the ack:

binding "pii_in": on_error 'closed' requires fail_closed_ack — a dead detector becoming an outage is a decision an operator must type out

An external tier requires external: allow

An external judge requires destination consent before it can send request text. Consent alone does not enable every registered detector: the stock gateway rejects sidecar bindings until their pinned runtime is qualified, rejects external detectors that require raw content, and rejects spanless external mutation. This example permits no judge spending and therefore makes no judge calls:

guardrails:
  judge:
    external: allow                # the air-gap gate
    api_key_env: ANTHROPIC_API_KEY
    model: claude-haiku-4-5
    timeout_ms: 2000
    max_usd_per_request: 0         # explicit zero: deny before any judge call

Budgets, and what overrunning one costs

local_budget_ms bounds cumulative local inspection work for one request across input, secondary preparation, output and stream phases; provider wall-wait time is excluded. Exhaustion discloses budget_exceeded and applies the effective failure posture. An acknowledged enforcing closed binding refuses release; monitor and open bindings retain their documented behavior.

Measure the selected bindings on representative traffic before enforcing them. The sample value of 50 ms is a configuration example, not a latency or coverage guarantee.

Profiles

A profile is a named set of binding ids. default_profile is what anonymous or keyless traffic gets; setting it to "" means such traffic is unguarded.

  profiles:
    standard: [pii_in]
    full:     [pii_in, pii_out, sec_in, inj_in]
  default_profile: standard

The resolved profile and the config hash ride every row as policy_ref — standard@cfgc935358 — so a row can always be traced back to the policy that produced it.