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 subagents as well (a denied tool is unavailable on the subagent 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:
- The desktop pops an approval dialog showing the tool name, parameters and impact.
- You pick:
- ✓ Allow (once)
- ✓ Always allow: adds tool+parameter pattern to the allow list.
- ✗ Deny
- 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 -rfargument 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. Subagents can recursively inherit the mode on demand, and messages produced under inheritance carry the same marking.
13.2.2 Local mode: cut the built-in internet tools in one click
The exact opposite direction from unrestricted mode — local mode switches off this session's built-in internet capability in one go, which suits material you'd rather not send out, or an environment with no connectivity anyway.
Where the switch is: the internet toggle in the input area. The default is "Internet tools enabled"; clicking raises a "Disable internet tools?" confirmation, and confirming applies it.
What gets switched off:
- Web fetch and search
- GitHub search
- VirusTotal / GTI threat-intel cloud lookups
- Online vulnerability DB sync
What is not affected (important — don't read this as "the network is off"):
- Network access from shell commands (e.g.
curl) — this switch does not block it - Network access from external MCP tools
- Communication with the model service itself
Effect on model choice: in local mode, this session's data only goes to the model the session itself uses —
code.ask,sec.decompileand memory auto-extraction no longer pick a 澜砥 model by routing; they always use the current session's model;- subtasks always use the main session's model (ignoring the subtask routing strategy and any model in the subagent definition);
- hooks use the model of the session that triggered them; if it can't be determined, that hook's model call is skipped rather than using another session's model;
- routines posted into a local-mode session use that session's model.
Scope: per session, and internet tools are restored automatically after a restart; subagents inherit the restriction. While it's on, tasks that rely on internet research (looking things up, cloud threat analysis, pulling the latest vulnerability data) will be noticeably limited — that's expected.
Slash command: type /local in the input box to toggle it.
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.
