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
| Field | Type | Default | Notes |
|---|---|---|---|
version | 1 | 1 | Schema version. Tightening changes bump this. |
description | string | "" | Free-form; shown in the dashboard. |
fail_mode | "open" | "closed" | "open" | Default for detectors with no matching on_failure. |
global_timeout_ms | int ≥ 1 | 5000 | Per-detector timeout if a stage doesn’t override. |
series_mode | "exhaustive" | "early_return" | "exhaustive" | How the cascade terminates. (See note below.) |
stages | DetectorStage[] | [] | Cascade plan. Empty ⇒ synthesise one parallel stage of every enabled detector. |
detectors | dict<name, DetectorConfig> | {} | Per-detector settings keyed by detector name. |
budgets | Budgets | null | null | Cost 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.
| Field | Type | Default | Notes |
|---|---|---|---|
name | string | null | null | Optional label for logs and the dashboard. |
direction | "request" | "response" | "both" | "both" | Which side of the proxy this stage runs on. |
detectors | string[] | [] | Detector names referenced from the detectors map. |
timeout_ms | int ≥ 1 | null | null | Per-detector cap. Null ⇒ inherit global_timeout_ms. |
decision | ActionThresholds | null | null | Early-return decision band (currently unused; see series_mode note). |
DetectorConfig
One entry in detectors. Configures one detector.
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | bool | true | Disable without removing from stages. |
weight | float ≥ 0 | 1.0 | Weight in the combiner. |
thresholds | ActionThresholds | {flag: 0.5, block: 0.85} | Score → effect mapping. |
category_overrides | dict<category, ActionThresholds> | {} | Per-category threshold tweaks. |
allowed_types | string[] | [] | Types this detector should skip (passthrough). |
parameters | dict | {} | Adapter-specific config. Frozen at deployment in v1. |
on_failure | FailureHandler[] | [] | Per-cause failure handling. Empty ⇒ inherit global fail_mode. |
ActionThresholds
| Field | Type | Default | Notes |
|---|---|---|---|
flag | float in [0, 1] | 0.5 | Confidence ≥ flag ⇒ at least Flag. |
block | float in [0, 1] | 0.85 | Confidence ≥ block ⇒ Block. Must be ≥ flag. |
FailureHandler
| Field | Type | Notes |
|---|---|---|
cause | "timeout" | "error" | What failed. |
action | "continue" | "block" | "flag" | What to do. |
Mapping to verdict effect:
| Action | Effect |
|---|---|
continue | Allow (cascade proceeds) |
flag | Flag (non-decisive; cascade proceeds) |
block | Block (cascade halts) |
If no handler matches the (detector, cause), the policy’s global fail_mode applies (open → Allow, closed → Block).
Budgets
| Field | Type | Default | Notes |
|---|---|---|---|
cost_usd_per_day | Decimal | null | null | Rolling 24h cap. |
cost_usd_per_month | Decimal | null | null | Rolling 30d cap. |
on_exceeded | BudgetExceeded | required | What 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 }| Field | Type | Notes |
|---|---|---|
secret_ref | string [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:
- Schema — every field is type- and range-checked. Closed enums (
fail_mode,series_mode,direction, etc.) reject unknown values.extra: forbidrejects unknown top-level keys. - Registry — every detector name in
stages[].detectors[]anddetectors[]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: 1description: "Engineering — default policy"
fail_mode: closedglobal_timeout_ms: 5000series_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 }