13. Tool permissions and approval

AVL Code applies fine-grained policy to every tool call.

13.1 Three-state permission

Each tool:

  • Allow: pass through.
  • Ask: pop an approval modal on every call.
  • Deny: reject directly.

Configurable per work mode; common patterns: enable write tools under execute, disable all writes under plan. The three states apply to sub-agents as well (a denied tool is unavailable on the sub-agent side too), and leftover tool config is cleaned up automatically after a plugin / external service is uninstalled.

13.2 Approve before use

When a tool marked "Ask" is about to run:

  1. The desktop pops an approval dialog showing the tool name, parameters and impact.
  2. You pick:
    • Allow (once)
    • Always allow: adds tool+parameter pattern to the allow list.
    • Deny
  3. The dialog shows a 30-second countdown; no response by the end counts as Deny.

13.2.1 Unrestricted mode (advanced)

To the right of the mode slider in the input area is a shield switch, for advanced users who know what they're doing. Turning it on goes through a confirmation dialog (with a 5-second cooling-off — the confirm button starts disabled and counts down "Please read the risk note 5s…"; it can't be clicked until it reaches 0, and Enter also doesn't activate it). Once on, a red banner stays put as a reminder; toggling off takes effect immediately.

Scope: per-session, in-memory only; cleared on restart.

On removes three frictions:

Friction When unrestricted
Tool approval Skip the approval modal (no per-call ask / deny / defer); tools execute directly
Command allow-list fs.exec is no longer restricted by the command allow-list
Network filter web.fetch / web.bing no longer filter internal / loopback / link-local addresses

Hard guards still apply (unaffected by the switch):

  • samples/ sandbox isolation.
  • rm -rf argument validation.
  • The injection-denylist (fork bombs / writing /etc / curl|sh / eval).
  • The http(s) protocol allow-list.

Slash-command shortcut — type directly in the input box:

  • /unrestricted (or Chinese alias /无限) — toggle the current session's unrestricted mode. Turning on still goes through the 5-second risk-confirmation dialog; turning off is immediate. The Chinese alias is hidden from the command palette and /help (avoids a duplicate row) but still executes when typed.

Message marking for the no-guardrails span: the consecutive messages produced while unrestricted mode is on are enclosed as a whole by a light border — start and end at a glance, so a later review shows immediately which content was generated without guardrails. Toggling off closes the border on the spot; while the mode is still on, no premature "end" boundary is drawn. Sub-agents can recursively inherit the mode on demand, and messages produced under inheritance carry the same marking.

13.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

13.4 Multi-device approval

The same approval request shows up on the desktop dialog and every bound remote channel (e.g. WeChat); the first response wins, and later replies from other devices are reported as already answered. A commonly-confused rule: the deny > defer > ask > allow priority order belongs to the hook layer — it merges permission decisions returned by multiple hooks within one evaluation, and has nothing to do with multi-device responses.

13.5 Remote approval

If WeChat is bound, every "Ask" approval mirrors to the bound chat. Reply with:

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

13.6 Persistence

Approval decisions are not stored in a separate audit log: only "Always allow" is persisted — written to the workspace-level authorization file hook-approvals.yaml (authorization fingerprint + decision time), viewable and revocable under Settings → Hooks. "Allow once" and "Deny" affect only the current call and leave no record.