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
- Open
/policies— pick the class - The versions rail appears. Click + New draft
- 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: 1description: "Starter policy — null detector, fail-open"fail_mode: openglobal_timeout_ms: 5000series_mode: exhaustive
stages: - name: baseline direction: both detectors: [null]
detectors: null: enabled: true weight: 1.0 thresholds: flag: 0.5 block: 0.85It 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: blockOnce 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:
| Error | Likely cause |
|---|---|
/fail_mode must be one of: open, closed | typed 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 <= block | thresholds 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
PolicyBodyschema —extra: forbidis strict
The schema is served at GET /api/v1/policy/schema.json if you want to inspect it directly.