shell.exec is fine until the command is rm -rf, db.query is fine
until it hits prod. That distinction is what an argument clause
expresses: a jsonpath tool argument
predicate that matches on the values an agent passes, so the verdict
fires only on the dangerous call and leaves the rest alone.
This page is a cookbook — a handful of copy-paste args_match_json recipes
for the cases that come up most. For the full clause grammar, operator table,
and fail-closed semantics, see
Validate arguments and the
Rule schema reference.
1. How a jsonpath tool argument clause works
A rule’sargs_match_json is a JSON-encoded string carrying a set of
clauses, all AND-ed together. The decoded value is an object,
{"clauses": [ … ]}, where each clause is a { path, op, value } triple:
path— a small JSONPath subset over the tool’s argument object:$.command,$.foo.bar,$.items[0], or$for the whole object. No wildcards, filters, slices, or recursive descent.op— one of a closed set:eq,contains,regex,in,cidr_match,gt,lt.value— the literal to compare against (a string, number, bool, or — forin— a JSON array).
tool_name_glob: the rule fires only
when the tool name matches and every clause holds. Omit args_match_json
entirely (or leave it an empty "{}") and the rule matches on the glob alone.
Clauses fail closed — the rule, not the request. If a path doesn’t
resolve, the arguments are malformed, or a value is the wrong type, the
clause evaluates false and the rule simply doesn’t fire — the call
falls through to the next rule or the default verdict. A broken clause
never auto-denies. Write your hard backstop as a plain glob
deny, not as
a clause you’re relying on to fail a certain way.2. Recipe: block one destructive command
The canonical case. Allowshell.exec in general, deny it only when the
command looks destructive. A regex clause on $.command does it:
$.command (or a missing one) never matches, so a malformed call falls
through rather than getting wrongly blocked.
3. Recipe: deny a tool against a named environment
Letdb.query run, but only against safe connections — deny it when the
target is prod or a replica. The in operator matches the resolved
value against any element of a JSON array:
in value must be a JSON array — a non-array is rejected when you
save the rule. Elements compare with scalar equality, so numbers and
strings each match their own type.
4. Recipe: deny a private-IP or metadata destination
When a tool takes a target IP as an argument,cidr_match tests whether it
falls inside a CIDR — the SSRF shape of “an agent fetching 10.x or the
cloud metadata address”:
5. Recipe: cap a numeric argument
gt and lt compare numbers. Use them to refuse an absurd batch size, an
oversized limit, or any runaway count — here, deny a bulk delete that
targets more than 100 rows:
"500" is a
type mismatch and does not match, so the rule won’t fire on a
stringly-typed argument. Keep the argument numeric, or normalize it before
the tool sees it.
6. Recipe: combine clauses (AND)
All clauses in one rule AND together, so you can narrow a verdict to a very specific call — for example, denyshell.exec only when it’s a
destructive command and it’s pointed at a prod host:
args_match_json — author
two rules (or two globs) at different priorities. The engine walks rules in
priority order and the first match wins, so put the narrow rules first.
See Rule priority.
7. Pick the verdict for the matched shape
A clause decides which calls match; the rule’sverdict decides what
happens. deny is the cookbook default, but the same clause can carry a
softer verdict:
sanitize — redact a secret in an argument
sanitize — redact a secret in an argument
When the matched argument carries a secret or PII rather than a
dangerous instruction,
sanitize redacts the matched substrings from
the tool arguments and forwards the cleaned call. It redacts
arguments only — never the content a tool returns. See
Sanitize responses.pending_approval — hold the matched call for a human
pending_approval — hold the matched call for a human
Hold exactly the risky shape for review instead of blocking it
outright: a reviewer approves or rejects out-of-band, and the agent
re-submits the approved call once. See
Approvals.
audit — just see it, for now
audit — just see it, for now
Set the verdict to
audit to record the matched call without blocking
while you tune the clause. Pair with
shadow mode to measure a deny
against live traffic before it changes anything.8. Test the clause before you depend on it
The console Test tab dry-runs a policy against a sample tool call and returns the verdict, the matched rule, and the reason — nothing is dispatched, nothing is persisted. Paste a realistic argument object and confirm the clause fires on the calls you mean and only those, since a clause that can’t resolve a value silently doesn’t fire. See Test rules.Clauses are validated strictly on save — unknown operators, bad paths,
a non-array
in value, an uncompilable regex, and invalid CIDRs are all
rejected, so a malformed clause can’t be persisted in the first place.9. Who can author argument clauses
All of this runs in the console under your session (/api/workspace/firewall/*):
| Action | Role |
|---|---|
| Read policies, presets, discovered tools | Member |
| Create / edit / delete rules | Developer+ |
| Test sandbox (dry-run a policy) | Developer+ |
| Read events and run aggregates | Developer+ |
Related
Validate arguments
The argument-matching use-case in full.
Block tools
Deny a whole tool by name — no clause needed.
Egress control
Govern outbound host / IP / CIDR destinations.
Rule schema
Every field a rule can carry.
Rule priority
First match wins — order narrow before broad.
Dangerous tool calls
The threat these recipes address.
