[FEATURE] Mods API: an observe-only event for every final tool denial, with its source and protected paths
Status Open
Reported on v2.1.296
Maintainer reply None cached
Workaround ✓ Mentioned in description ↑
Activity 0 comments · opened Oct 11, 2026
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
Claude Code 2.1.296, macOS. The Arrester mod opens a "block" when a hook, rule or the auto-mode classifier refuses a tool call, then stops detours to the same files. Two denials escape it:
- Managed-settings hooks. The types say: "The chain is [managed settings hooks, ...hooks modules, the other settings hooks as core], so a managed block ends it above every module." A managed JSON deny reaches no mod.
- Recursive searches. A denied
grep -r, Grep or Glob names no file.PermissionDeniedHookInputcarries onlytool_name,tool_input,tool_use_id,reasonandmcp_server?.ToolCheckResult.hookis "Absent on a$.tool.checkquery, which runs no classic hook", so the mod cannot ask either.
Proposed Solution
- An observe-only event, raised after the final decision refuses a tool call from any source, managed hooks included. Its return value is ignored, so managed policy still wins.
'tool.denied': {
tool: string; tool_use_id: string; agentId?: string; input: unknown;
source: 'rule' | 'mode' | 'classifier' | 'hook' | 'plugin' | 'user';
scope?: SettingsSource | 'plugin'; hook?: string; rule?: string;
reason: string; paths?: string[];
}
- An optional
paths: string[]in a PreToolUse deny'shookSpecificOutputand in the classifier verdict, passed ontool.deniedandclassic.PermissionDenied.
Alternative Solutions
Arrester's documented workaround is an exit-code-2 block instead of a JSON deny. A user cannot change a managed hook.
Priority
Medium - Would be very helpful
Feature Category
Developer tools/SDK
Use Case Example
- A managed hook denies
cat .envwith JSON. - Claude tries
cp .env /tmp/x && cat /tmp/x. - With
tool.denied, Arrester blocks.envand stops the copy. Today it sees nothing. - A hook denies
grep -r TOKEN .withpaths: [".env"]. Arrester then stopshead .env.
Additional Context
Closes two Arrester "Known limits". Related: #72589 (denial reason and type on PermissionDenied, classifier only, no paths) and #96026 (deciding rule, SDK side).