VS Code extension: PreToolUse 'ask' permission tier (static rules + hooks) silently resolves to allow, no prompt shown
Summary
In the VS Code extension (default permission mode), a tool call that should be escalated to a permission prompt — because it matches a static "ask" permission rule, or because a PreToolUse hook returned hookSpecificOutput.permissionDecision: "ask" — instead runs immediately with no prompt shown to the user. The same rule/hook combination behaves correctly (blocks in headless, and per our reading of the docs, should prompt interactively) when reproduced via the headless CLI.
This means an "ask"-tier permission control (static rule or hook) is currently a silent no-op in the VS Code extension's default permission mode — it neither blocks nor visibly prompts; the tool call simply proceeds as if it had been allowed.
Environment
- Claude Code CLI 2.1.198
- VS Code extension, recorded session
permissionMode: "default" - Reproduced with both (a) a static settings.json permission rule of the
"ask"tier, and (b) aPreToolUsehook returningpermissionDecision: "ask"
Headless baseline (behaves as documented)
Using claude -p in isolated temp projects, permission precedence matched the documented order (deny → ask → allow) in every case we tried:
- A settings
allow: ["Bash(echo:*)"]rule plus aPreToolUsehook returningpermissionDecision: 'ask'for the same command → the call is blocked (headless can't prompt, so it fails closed) with the hook's stated reason. Hook-askcorrectly overrides a standingallowrule. - Same result under
--permission-mode bypassPermissions— hook-askstill blocks headless. - A static
"ask"rule correctly overrides a same-scope"allow"rule. - A static
"ask"rule correctly overrides a broader-scope"allow"rule (project-levelaskvs. user-levelallow).
So headless enforcement of the ask tier — both static rules and hook-emitted decisions — matches the documented precedence in every combination we tested.
VS Code extension (diverges from the above)
In a live, interactive VS Code extension session (same permission configuration, permissionMode: "default"):
- A
Bashcommand matching a project-level static"ask"rule (and matching no"allow"rule at any scope — checked user, project, and local settings) ran immediately, with no permission prompt. - The same result for a
WebFetchcall: aPreToolUsehook returnedpermissionDecision: "ask"for a non-allowlisted host, and the fetch executed immediately with no prompt and no visible indication the hook's decision was overridden. - For comparison,
"deny"-tier decisions (both a static deny rule and a hook returningpermissionDecision: "deny") do work correctly in this same environment — those calls visibly block with the stated reason. Only theasktier is affected.
Expected vs actual
- Expected: a tool call matching an
"ask"-tier decision (static rule or hook) shows the user a permission prompt in the VS Code extension, same as it does (per the docs) in other interactive contexts. - Actual: the entire
asktier is silently resolved to allow in the VS Code extension's default permission mode — no prompt, no log entry visible to the user, the call simply proceeds.
Impact
Any project relying on "ask"-tier permission rules or hook-emitted ask decisions as a safety control — expecting the user to be asked before a risky action proceeds — gets no protection at all in the VS Code extension, with no indication anything was skipped. We only discovered this by explicitly testing whether a prompt appeared; from the tool-call's perspective (exit code, hook stdout) everything looked like normal ask-path handling. We've had to work around this by defaulting the affected controls in our own hooks to hard-deny instead of ask, since ask currently provides no actual protection in this environment.
Suggested fix
Either make the VS Code extension's default permission mode surface the prompt for ask-tier decisions (matching headless/interactive-terminal behavior), or, if this is an intentional divergence for the extension, document it clearly so hook/rule authors don't unknowingly rely on ask as a working control there.
Happy to share the minimal repro harness (settings.json + hook scripts) if useful.