Skip to content

Write a policy

This guide walks through authoring a policy from scratch using the dashboard’s YAML editor. For the full field reference, see Reference → Policy schema.

Where to find the editor

  1. Open /policies — pick the class
  2. The versions rail appears. Click + New draft
  3. The editor opens, pre-loaded with the active version’s body (or v1 if nothing is published yet)

The editor is a YAML pane with line numbers and a side panel for the source version and live validation.

A starter policy

If you’re writing your first policy, start from this:

version: 1
description: "Starter policy — null detector, fail-open"
fail_mode: open
global_timeout_ms: 5000
series_mode: exhaustive
stages:
- name: baseline
direction: both
detectors: [null]
detectors:
null:
enabled: true
weight: 1.0
thresholds:
flag: 0.5
block: 0.85

It enables the null detector (which always returns Allow), which proves the cascade machinery is wired without actually doing detection. Use it as a stepping stone.

Adding a real detector

Once you have Presidio or RegexDetector wired into your deployment, replace the stages and detectors blocks:

stages:
- name: cheap-inline
direction: request
detectors: [regex]
timeout_ms: 100
- name: pii-scan
direction: both
detectors: [presidio]
timeout_ms: 2000
detectors:
regex:
enabled: true
weight: 1.0
thresholds: { flag: 0.5, block: 0.85 }
presidio:
enabled: true
weight: 1.0
thresholds: { flag: 0.5, block: 0.85 }

Note that regex runs on request only (cheap inspection of the prompt), but presidio runs on both (we want to catch PII in the response too).

Adding a budget

budgets:
cost_usd_per_day: 50.00
cost_usd_per_month: 1000.00
on_exceeded:
action: block

Once budgets are present, the proxy checks spend before forwarding upstream. See Concepts → Tokens and budgets.

Validation while you type

The editor validates against the policy JSON Schema in real time. The side panel shows:

  • valid — green dot. The Save button enables.
  • parse error — YAML can’t be parsed. The panel shows the parser’s complaint.
  • N schema errors — YAML parses but doesn’t fit the schema. The panel lists every error with its instance path and a human-readable message.

Common schema errors:

ErrorLikely cause
/fail_mode must be one of: open, closedtyped closing or similar
(root) unexpected property "foo"typo at top level
(root) missing required: "detectors"left a required field out
/detectors/<name>/thresholds/flag must be <= blockthresholds inverted

Saving

The Save as draft button is enabled only when:

  • the body is clean (parses + validates), and
  • the body differs from the source version

Clicking creates a new draft (published_at: null) and redirects to the versions page. The new draft does not become active until you publish it.

What’s not allowed in the body

The body is the runtime config — not the metadata. Don’t put these in the YAML:

  • id, class_id, version, published_at — these are columns on the policy row
  • Anything not in the PolicyBody schema — extra: forbid is strict

The schema is served at GET /api/v1/policy/schema.json if you want to inspect it directly.