Use policies to allow, require approval for, or deny tool calls. Reference a policy file from an
agent definition, or write the rules inline.
allow : [ web_search , linear/* , write_file(notes/*) ]
github/create_* : This opens an issue on GitHub.
books/create_bill(amount >= 1000) : Bills of $1,000 or more require approval.
budget : { usd : 5.00 , per : day }
A policy is policies/NAME.yaml in the config directory . Reference it with policy: NAME, or write rules inline.
The daemon reads policies/ at startup. Restart it after a change.
The strictest rule wins: deny, then ask, then allow.
See Policy for examples.
Key
Value
Description
allow
patterns
calls that run
ask
patterns, or pattern to message
calls that need approval; the message is shown to the approver
deny
patterns, or pattern to message
calls that are denied; the message is returned to the model
default
allow, ask, deny, or a map from annotations to decisions
calls no rule matches; default allow
allow_after
a map from labels to tool patterns
calls still allowed after the turn reads content with that label
budget
the agent's spend limit
judge
yes-or-no questions a model answers about each call
Pattern
Matches
web_search
one tool
github/*
every tool of the MCP server github
github/create_*
its tools starting with create_
write_file(notes/*)
calls on a path under notes/
books/create_bill(amount >= 1000)
calls whose amount is 1000 or more
email/send(to != *@acme.com)
calls whose to isn't at acme.com
bank/transfer(amount > 5000, currency = USD)
calls where every condition matches
* matches any characters, including /.
The model sees github/create_issue as github__create_issue. A pattern matches either form.
Conditions: =, !=, >, >=, <, <=. = is case-insensitive and supports *.
vendor.name is a nested argument. On a list, lines.amount must match every item.
A condition on a missing argument never matches.
Write name = value, not name: value. YAML parses : as a key.
allow : [ write_file(notes/*) ]
else applies to tools with none of the annotations. If a tool has several, the strictest wins.
Gated tools require explicit permission or approval. After the agent reads untrusted content,
allow is insufficient: the tool must also be listed under allow_after to run without approval.
An explicit ask or deny rule still takes precedence. See Gated tools
and Untrusted content .
Key
Default
Description
usd
limit in US dollars
tokens
limit in tokens, input and output together
per
day
turn, day, week, month or total
timezone
Etc/UTC
time zone for day, week and month boundaries; weeks start Monday
grant
one more limit
the amount an approval adds, as {usd: 2.00}
price
{input: 0.60, output: 2.20} per million tokens, for a model with no known price
on_exhausted
ask
ask for approval, or deny
Checked before each model call. The call that crosses the limit still runs.
Reported tool costs count toward spending, but budgets do not block tool calls.
A dollar budget refuses a model with no price unless price is set. config.yaml's models sets prices.
An organization’s policy, set in orgs , has one budget shared by all its agents.
GET /v1/owners/{owner}/ceilings returns the spend.
model : typesafe:jev-latest
- question : Does this call send money to an account outside the company?
Key
Description
model
the judge model; default typesafe:jev-latest
questions[].question
required; the question about the call
questions[].tools
patterns it applies to, without arguments; default: every tool
questions[].deny
deny at or above this probability (0 to 1)
questions[].ask
require approval at or above this probability
questions[].allow
allow below this probability
questions[].message
the approval or denial message, instead of the question
A question needs at least one of deny, ask and allow.
The judge runs after the rules, and never overrides a rule's ask or deny.
A judge's allow applies only to calls no rule matches, and never after reading untrusted content.
If the judge model fails, the call needs approval when the question has ask or deny.
Arguments can be crafted to fool a judge. Keep exact checks in rules.