14. Tool permission policy

[!ref] Full details in the User Manual, "Tool permissions and approval".

14.1 Three-state semantics

State Icon Behaviour
Allow Pass through; no modal
Ask Modal on every call (wired into the real confirmation flow; the call pauses until approved)
Deny Reject directly; logged to error drawer

The three states apply to sub-agents as well: "Deny" takes effect on both the main agent and sub-agents (fail-closed on the sub-agent side — the tool is simply not visible); uninstalling a plugin / removing an MCP backend auto-cleans leftover tool-config keys, keeping on-disk config in line with the tools actually available.

14.2 Decision aggregation and multi-device response

Hook decision aggregation — when several hooks return permission decisions within one evaluation, they merge by (first wins):

deny > defer > ask > allow

Multi-device response — when the desktop dialog and a remote channel (WeChat etc.) receive the same request, the first response wins; later replies from other devices are reported as already answered.

14.3 Always-allow granularity

Granularity Coverage When to use
Once only Single call Cautious evaluation
Same tool + same args One specific call shape Recommended default
Same tool + any args Any call to this tool Internal scripts
Entire workspace Every tool in this workspace Isolated environments only

14.4 Remote-approval reply

Command Equivalent desktop action
/approve <id> Allow once
/always <id> Always allow
/deny <id> Deny
No reply Times out as deny when the 30 s countdown ends

14.4.1 Unrestricted mode (advanced)

Shield switch to the right of the mode slider; per-session, in-memory only, cleared on restart. 5-second cooling-off on open.

Removed When unrestricted
Tool approval Skip the approval modal; execute directly
Command allow-list fs.exec unrestricted
Network filter web.fetch / web.bing don't filter internal / loopback / link-local

Hard guards still apply (unaffected by the switch):

Hard guard Description
samples/ sandbox Cannot be lifted
rm -rf arg validation Still validates
Injection deny-list Fork bombs / /etc writes / curl|sh / eval
Protocol allow-list Only http(s)

Message marking: the consecutive messages produced while the mode is on are enclosed as a whole by a light border (start / end boundary marks); toggling off closes it on the spot, and no "end" mark is drawn while the mode is still on. Sub-agents can recursively inherit the mode on demand; messages produced under inheritance carry the same marking.

14.5 Approval request fields and persistence

Fields carried by the approval dialog (hook:ask event):

Field Description
request_id Approval id
event Triggering hook event name
fingerprint Authorization fingerprint ("Always allow" matches on it)
handler_type / handler_label Handler type and display name
matcher / match_target Matched matcher and match target
source_scope / source_id Source scope (plugin / user / workspace) and its id
session_id Session id
timeout_sec Countdown seconds (30)

Decision values: deny / allow_once / always_allow.

Persistence — only "Always allow" is persisted: it is written to the workspace-level hook-approvals.yaml (authorization fingerprint + decision time), viewable and revocable under Settings → Hooks. "Allow once", "Deny" and timeouts affect only the current call and are not stored.