Auto-mode permission decider denies remediation-gated retries after PreToolUse hook denial
Summary
Intent-aware gating vs shape-aware gating: the shape-aware version creates the bypass surface it's trying to prevent.
In defaultMode: auto with skipAutoPermissionPrompt: true, the permission decider pattern-matches prior tool call denied by a PreToolUse hook → same-intent retry as a bypass, even when the deny reason's remediation was completed between the two calls.
Minimal reproducer
~/demo/deny-then-allow.mjs:
#!/usr/bin/env node
import { existsSync, writeFileSync, mkdirSync } from 'fs';
const marker = '/tmp/decider-repro/denied';
let raw = ''; for await (const c of process.stdin) raw += c;
const input = JSON.parse(raw);
if (input.tool_name === 'Bash' && !existsSync(marker)) {
mkdirSync('/tmp/decider-repro', { recursive: true });
writeFileSync(marker, '1');
process.stdout.write(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason: 'Read README.md first, then retry.',
},
}));
}
process.exit(0);
~/.claude/settings.json (minimal):
{
"permissions": { "defaultMode": "auto" },
"skipAutoPermissionPrompt": true,
"skipDangerousModePermissionPrompt": true,
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "node ~/demo/deny-then-allow.mjs",
"timeout": 5
}]
}]
}
}
Sequence:
rm -rf /tmp/decider-repro && mkdir /tmp/test-repo && echo hi > /tmp/test-repo/README.md- Ask Claude Code to run
ls /tmp/test-repo. Hook denies with"Read README.md first, then retry." - Ask Claude Code to Read
/tmp/test-repo/README.md. Read succeeds. - Ask Claude Code to retry
ls /tmp/test-repo. Hook no longer denies (marker set). Auto-mode denies the retry with a reason about"retry after guard block bypass pattern"that does not reference the intervening Read.
Expected
Step 4 allowed. The hook's deny reason named the remediation ("Read README.md first"); the agent performed it; the retry should proceed.
Actual
Step 4 denied by auto-mode. Agents adapt by changing command shape (-F commit-msg-file for git commit, tool-swap Edit→Bash, etc.) to slip the pattern matcher ... the exact behavior the pattern is meant to catch.
Requested fix
A Read of X.md after a deny telling the agent to read X.md should not cause the next tool call to be denied as a bypass. The mechanism is for you to determine.
Environment
- Claude Code
2.1.116 - macOS 26.2 (darwin 25.2.0)
~/.claude/settings.json:"permissions": { "defaultMode": "auto" }+"skipAutoPermissionPrompt": true+"skipDangerousModePermissionPrompt": true. This combination activates the silent auto-mode decider that emits the denial reason referenced above.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗