Skip to content

Policy schema reference

A PolicyBody describes what the proxy does for one class. This page documents every field.

The authoritative source is GET /api/v1/policy/schema.json — generated from the Pydantic models. Use that for client-side validators and editor autocompletion.

Top-level

FieldTypeDefaultNotes
version11Schema version. Tightening changes bump this.
descriptionstring""Free-form; shown in the dashboard.
fail_mode"open" | "closed""open"Default for detectors with no matching on_failure.
global_timeout_msint ≥ 15000Per-detector timeout if a stage doesn’t override.
series_mode"exhaustive" | "early_return""exhaustive"How the cascade terminates. (See note below.)
stagesDetectorStage[][]Cascade plan. Empty ⇒ synthesise one parallel stage of every enabled detector.
detectorsdict<name, DetectorConfig>{}Per-detector settings keyed by detector name.
budgetsBudgets | nullnullCost caps.

series_mode note

exhaustive runs every stage, combines all signals, decides once at the end (Block from any stage still halts immediately).

early_return is intended to stop at the first stage that produces a decisive verdict — useful when cheap early stages can short-circuit expensive later ones. In v1, early_return is equivalent to exhaustive because the “decisively clean” branch requires detector scores to drive a confidence band; without those, only Block halts the cascade either way.

DetectorStage

One element of stages. Detectors within a stage run in parallel; stages run in declared order.

FieldTypeDefaultNotes
namestring | nullnullOptional label for logs and the dashboard.
direction"request" | "response" | "both""both"Which side of the proxy this stage runs on.
detectorsstring[][]Detector names referenced from the detectors map.
timeout_msint ≥ 1 | nullnullPer-detector cap. Null ⇒ inherit global_timeout_ms.
decisionActionThresholds | nullnullEarly-return decision band (currently unused; see series_mode note).

DetectorConfig

One entry in detectors. Configures one detector.

FieldTypeDefaultNotes
enabledbooltrueDisable without removing from stages.
weightfloat ≥ 01.0Weight in the combiner.
thresholdsActionThresholds{flag: 0.5, block: 0.85}Score → effect mapping.
category_overridesdict<category, ActionThresholds>{}Per-category threshold tweaks.
allowed_typesstring[][]Types this detector should skip (passthrough).
parametersdict{}Adapter-specific config. Frozen at deployment in v1.
on_failureFailureHandler[][]Per-cause failure handling. Empty ⇒ inherit global fail_mode.

ActionThresholds

FieldTypeDefaultNotes
flagfloat in [0, 1]0.5Confidence ≥ flag ⇒ at least Flag.
blockfloat in [0, 1]0.85Confidence ≥ block ⇒ Block. Must be ≥ flag.

FailureHandler

FieldTypeNotes
cause"timeout" | "error"What failed.
action"continue" | "block" | "flag"What to do.

Mapping to verdict effect:

ActionEffect
continueAllow (cascade proceeds)
flagFlag (non-decisive; cascade proceeds)
blockBlock (cascade halts)

If no handler matches the (detector, cause), the policy’s global fail_mode applies (openAllow, closedBlock).

Budgets

FieldTypeDefaultNotes
cost_usd_per_dayDecimal | nullnullRolling 24h cap.
cost_usd_per_monthDecimal | nullnullRolling 30d cap.
on_exceededBudgetExceededrequiredWhat to do when a cap is hit.
interface BudgetExceeded {
action: "block" | "flag" | "throttle";
}

throttle currently degrades to block (rate-limiting machinery is a roadmap item).

SecretRef

Some parameters fields take secrets. Use the typed reference form:

parameters:
api_key: { secret_ref: LAKERA_API_KEY }
FieldTypeNotes
secret_refstring [A-Z][A-Z0-9_]*Name of the secret in the runtime’s secret store.

The proxy resolves the secret at request time. Never put a literal secret in a string field — the schema linter will reject obviously-secret-shaped strings.

Validation discipline

Two layers:

  1. Schema — every field is type- and range-checked. Closed enums (fail_mode, series_mode, direction, etc.) reject unknown values. extra: forbid rejects unknown top-level keys.
  2. Registry — every detector name in stages[].detectors[] and detectors[] must resolve at request time. Unknown detectors are dropped from the stage; if a stage ends up empty it’s skipped.

Both run at admission (POST /policy/class/{id}/drafts). Errors are returned with field-level detail.

A complete example

version: 1
description: "Engineering — default policy"
fail_mode: closed
global_timeout_ms: 5000
series_mode: exhaustive
stages:
- name: cheap-inline
direction: both
detectors: [regex_pii]
timeout_ms: 100
decision: { flag: 0.5, block: 0.85 }
- name: hosted-scan
direction: both
detectors: [presidio]
timeout_ms: 2000
detectors:
regex_pii:
enabled: true
weight: 1.0
thresholds: { flag: 0.5, block: 0.85 }
category_overrides:
US_SSN: { flag: 0.3, block: 0.5 }
on_failure:
- { cause: timeout, action: continue }
- { cause: error, action: block }
presidio:
enabled: true
weight: 1.0
thresholds: { flag: 0.5, block: 0.85 }
parameters:
endpoint: { secret_ref: PRESIDIO_URL }
entities: [EMAIL_ADDRESS, US_SSN, PHONE_NUMBER]
on_failure:
- { cause: timeout, action: continue }
- { cause: error, action: continue }
budgets:
cost_usd_per_day: 100.00
cost_usd_per_month: 2000.00
on_exceeded: { action: block }