Rules decide what happens before each action.
A rule holds a condition written in CEL, the condition language of Google, a verdict and a mode. Before each action of each agent, Paidwen evaluates every rule of your organization.
You can also write a rule in your own words: Paidwen writes the CEL for you, reads it back and replays it before you confirm (see Plain language).
A condition reads six variables.
agent:name,team,owner,environment,risk_level,riskandlabels.teamis the handle of the team of the agent, likecustomer-support: it never changes when the team is renamed.owneris the email of the member who answers for the agent.riskis the level that Paidwen computes (see Risk score).tool:name,kindandserver.kindisfunction,httpormcp.params: the parameters, as the agent sends them.cost:estimated_usd,spent_today_usdandspent_month_usd, in US dollars.now: the time of the decision, in UTC.firewall:secrets,cards,ibansandemails, the values that the firewall found in the parameters, andinjection, the prompt injection score of the session (see Firewall).
A field that the request does not carry is absent, and Paidwen never replaces it with a value. A condition returns a boolean.
A rule returns one of five verdicts.
From the least strict to the strictest:
allow: the action runs.require_approval: a person of the approval group approves or denies the action.escalate: the action goes up to a manager, through the same circuit.block: the action never runs.quarantine: the action never runs, and the whole agent goes into quarantine.
When several active rules answer, the strictest verdict wins. With no permission, no spent budget and no active rule that answers, the verdict is allow. An agent therefore runs as before until you write your first rules.
The mode switches a rule between active and observe.
A rule in active mode applies its verdict. A rule in observe mode only records the verdict it would have returned, in the observed field of the decision and in the journal. The Rules screen switches a rule in one click, and the API does the same, in both directions and at any time:
PATCH /v1/rules/{rule_id}
Content-Type: application/json
{"mode": "observe"}The Rules screen creates a new rule in active mode. A rule created in observe mode shows what it would block before it blocks anything.
Conditions follow a few common shapes.
These rules are examples, not features: Paidwen knows no tool. You name your tools, and you write the conditions on their fields.
tool.name == "payments.refund" && params.amount > 500With require_approval, a refund above 500 waits for a person.
tool.name == "database.delete"With block, every deletion stops before it runs.
tool.name == "email.send" && params.recipients.size() > 1000With require_approval, a send to more than 1,000 recipients waits for a person.
cost.spent_today_usd > 80.0With escalate, an agent that spent more than $80 today sends each action to a manager.
tool.server == "api.payments.example.com" && params.body.amount > 50000A captured HTTP call carries its host in tool.server and its JSON body in params.body.
agent.environment == "production" && now.getHours("Europe/Paris") >= 22With require_approval, a production agent asks a person after 10 PM in Paris.
The API saves a rule only when its condition compiles.
POST /v1/rules
Content-Type: application/json
{
"name": "Refunds above 500",
"condition": "tool.name == \"payments.refund\" && params.amount > 500",
"verdict": "require_approval",
"mode": "observe"
}Paidwen compiles the condition with the same environment as the decision point before it saves the rule. A condition that does not compile, or that does not return a boolean, gets 400 with the CEL error, and nothing is saved. A saved change reaches every decision point in under a second.
A rule that returns require_approval or escalate can name its approval group in approval_group_id. The approvals page describes the groups.
A rule that reads an absent field does not apply.
params.amount on a request without an amount produces an error. That rule then does not apply, and the other rules apply as usual. In CEL, false && x is false even when x fails, so tool.name == "payments.refund" && params.amount > 500 only fails for a refund without an amount.
A security rule plans for the absent field, so that an agent cannot escape it by leaving the field out:
tool.name == "payments.refund" && (!has(params.amount) || params.amount > 500)Each evaluation stops at a cost limit.
Each evaluation stops at a cost of 1,000,000, the limit of Kubernetes for one expression. CEL has no free loop and no recursion, so a badly written rule can neither loop nor take the decision point down.
Rules have four limits.
- The variables are maps. A typo in a field name compiles, then fails at each evaluation, and the rule never applies.
nowis in UTC. A rule on the local time names its time zone, as innow.getHours("Europe/Paris").- Each decision evaluates every rule of the organization, so its time grows with their number.
- A rule never reads the journal or the agent's history: it reads only the six variables.