Skip to main content

Policies

A policy is one rule a Guard applies, such as "hide email addresses" or "block prompt injection". A guard is a list of them.

Its job​

A policy decides one thing about one piece of text: let it through, flag it, block it, or rewrite part of it. It says which checks it runs at, and it has a name that shows up in findings.

A policy doesn't decide the final outcome. The guard runs every policy that applies, and the check blocks if any of them blocks.

Mental model​

There are three kinds. They differ in where the decision is made.

KindWhere it runsWhat it doesExamples
TransformYour machineRewrites or inspects text with code: patterns, word lists, size caps.invisible_text, regex, substrings, allowed_tools, token_limit
Sensitive-data policyYour machineFinds values that must not leave, and jes replaces them.pii, secrets, canary
JudgmentThe decision modelAsks the model a typed question and compares its answer with your threshold.injection, hazards, toxicity, topics, tool_safety, judge(...)

A check runs in two steps. First the local policies run, in order, and sensitive values are replaced. Then the judgments see the cleaned text and are sent to the model together.

So a judgment never sees a value that pii or secrets found.

Using it​

You don't build policy objects by hand. You call a factory function, and it returns a ready policy:

from jes import Guard, YesNo
from jes.policies import injection, judge, pii, secrets

guard = Guard(
[
pii(["EMAIL_ADDRESS", "PHONE_NUMBER"]), # sensitive data, local
secrets(), # sensitive data, needs jes[secrets]
injection(threshold=0.8), # judgment
judge( # your own judgment
"refund_promise",
YesNo("Does the reply promise a refund?"),
threshold=0.7,
stages=("output",),
),
],
model="jev-latest",
)

To ask the model your own question, use judge(). You write the question with a question type, and the decision model answers it. To match text with code, write a Transform class. It needs a name, stages, a phase, and an apply(text, context) method that returns edits and findings. jes applies the edits. See Write your own policy.

Good to know​

  • Every judgment needs a threshold. jes ships no default. A threshold belongs to one model and one question. See Questions and thresholds.
  • Each policy runs only at its stages. pii runs at every check. injection runs on input, untrusted text, and tool calls. canary runs on replies and tool calls. Override stages= on the factory when you need to.
  • Names must be unique in a guard. A finding's policy is the name, so you can tell two regex policies apart.
  • You can't write your own sensitive-data policy. pii, secrets, and canary are built in, because jes owns how their values are replaced and restored. A custom Transform can still rewrite text.
  • Some policies need an extra. secrets() needs jes[secrets]. pii needs nothing for emails, phone numbers, and cards, which are patterns. Names (PERSON, on in pii() by default) need jes[pii] and a spaCy model, and raise PolicyError without them. See Installation.
  • Recipes are policies too. jes.recipes holds more judgments and transforms, such as language, json_check, and malicious_urls. See Built-in policies.

Next​