Skip to main content
Allow-listing a tool answers which tool an agent may call. It can’t answer with what arguments. shell.exec is fine for ls; it is a disaster for rm -rf /. db.query is fine against a replica; against prod it’s a liability. The difference lives in the arguments, and a tool-name rule can’t see it. The Firewall’s argument clauses (args_match_json) close that gap. They inspect the concrete arguments the model chose for a tool call and decide the verdict from their values — so you can permit a tool broadly while denying the one dangerous shape it can take. This page is the focused guide to authoring those clauses; for the full rule vocabulary see Firewall rules, and for the policy model around them, Firewall.
Argument values only exist once the model has chosen how to call a tool, so argument clauses belong on the response and mcp stages. On inbound — where the agent only advertises tool definitions — there are no call-time arguments to check.

1. When to validate tool call arguments

Reach for an argument clause whenever a tool is safe in general but dangerous in a specific shape:

Destructive commands

Allow shell.exec, but deny when the command matches rm -rf, mkfs, or dd if=.

Production blast radius

Allow db.query, but deny (or hold for approval) when the connection target is prod.

Internal destinations

Allow a fetch tool, but deny when its url/ip argument falls inside an RFC-1918 range or the cloud-metadata IP.

Oversized operations

Allow a bulk tool, but deny when a limit or count argument exceeds a numeric ceiling.
The rule still matches on the tool name first; the clauses narrow it from which tool to which call.

2. The shape of a clause set

args_match_json is a JSON-encoded string whose decoded value is an object holding a list of clauses. Each clause is a { path, op, value } triple, and all clauses AND together — the rule fires only when every clause is true. Decoded, the value looks like:
{
  "clauses": [
    { "path": "$.command",    "op": "regex",      "value": "rm -rf|drop table" },
    { "path": "$.connection", "op": "in",         "value": ["prod", "replica"] },
    { "path": "$.ip",         "op": "cidr_match", "value": "10.0.0.0/8" }
  ]
}
In a rule body the field carries that JSON as a single escaped string — e.g. "args_match_json": "{\"clauses\":[{\"path\":\"$.command\",\"op\":\"regex\",\"value\":\"rm -rf\"}]}". An empty or absent args_match_json is vacuously true — the rule matches on its tool-name glob alone, exactly as a name-only rule does.

3. Operators

Seven operators make up the closed vocabulary. The console validates the operator and its value shape when you save, so a malformed clause never persists.
OperatorMatches when
eqScalar equality (numbers compared numerically; a type mismatch is no match).
containsSubstring — both operands must be strings.
regexA Go RE2 pattern matches the string value (linear-time, no backreferences).
inThe value is an element of the given JSON array.
cidr_matchThe string IP falls inside the given CIDR.
gt / ltNumeric greater-than / less-than (strings are not coerced).

4. Path syntax

A clause’s path is a small JSONPath subset over the tool’s argument object:
Read a top-level or nested object field by name.
Index into an array, optionally continuing into the element’s fields.
Match against the entire argument blob (useful with contains or regex for a coarse scan).
There are no wildcards, filters, slices, or recursive descent — the grammar is deliberately small so matching stays linear-time and predictable on the hot path.

5. A worked example

You let your agents run shell.exec freely, but a recursive force-delete should never reach the shell. Author one response-stage rule that denies shell.exec only when the command argument looks destructive.
1

Open the rule editor

In the console, open the firewall policy attached to your agent’s key (or the workspace default) and add a rule. Editing policies is a Developer+ action — Members can read policies but not write them.
2

Match the tool on the response stage

Set the stage to response and the tool glob to shell.exec. The response stage carries the model’s chosen arguments, which the clause needs.
3

Add the argument clause

Add one regex clause on $.command, then set the verdict to deny:
{
  "stage": "response",
  "tool_name_glob": "shell.exec",
  "verdict": "deny",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.command\",\"op\":\"regex\",\"value\":\"rm\\\\s+-rf|mkfs|dd\\\\s+if=\"}]}"
}
args_match_json is a JSON-encoded string; its decoded value is the { "clauses": [ … ] } object shown in §2.
4

Dry-run it before you depend on it

Use the Test tab to evaluate the rule against a sample shell.exec call. It returns the verdict, the matched rule, and the reason — nothing is dispatched and nothing is persisted.
Now shell.exec with "command": "ls -la" flows through as before, while "command": "rm -rf /var" is denied. A deny on response lets the model see a tool error and react — pick another tool, ask the user, or stop — rather than crashing.
Want to permit the call but strip a leaked value instead of blocking? Swap the verdict to sanitize. Sanitize doesn’t redact what the clause matched — it runs a separate redactor (named presets like openai_key, anthropic_key, ssn_us, plus your own custom regexes) over the argument strings, replaces each hit with a [redacted:…] token, and forwards the cleaned call. The args_match_json clause still decides whether the rule fires; the sanitizer decides what gets scrubbed. See Sanitize arguments. Sanitize redacts tool-call arguments only — never the content a tool returns.

6. Clauses fail closed — the rule, not the request

If a clause can’t be evaluated — the path doesn’t resolve, the arguments are malformed, or a regex / CIDR is invalid — the clause evaluates to false and the rule simply does not fire. The call falls through to the next rule or the policy’s default_verdict. A broken clause never auto-denies and never disturbs the relay.
Because a clause that can’t evaluate makes its rule not match, never lean on a clause to fail a particular way. Author your “catch everything dangerous” rule as an explicit deny with its own tool glob, and use argument clauses to narrow a permit — not as your last line of defense.

7. Combining clauses with the rest of a rule

Argument clauses stack with everything else a rule expresses — they’re one AND-ed condition among several:
Combine withEffect
tool_name_globThe clause only runs once the tool name matches — name first, arguments second.
skill_name_globGate the same tool’s arguments differently by owning skill (e.g. stricter on community.*).
verdictPair clauses with deny, sanitize, pending_approval, or cap_cost, not just deny.
Multiple clausesAll must hold — combine a regex command check with an in environment check to scope a deny tightly.
For the precise verdict semantics each pairing produces, see Verdicts; for how a held call resolves, see Approvals.

8. Where this fits

Firewall rules

The complete rule reference — globs, clauses, sanitizers, egress, and sequences.

Argument cookbook

Copy-paste args_match_json recipes for the common dangerous shapes.

Firewall stages

Why argument clauses live on response and mcp, not inbound.

Block tools

Deny a tool outright when no argument is safe.
For the broader picture, see Dangerous tool calls and How OrcaRouter inspects.