Double-Check: It Runs Through the Rules Before Every Move
When Claude decides to call a tool, the system runs through a decision process before actually executing:
Claude decides to call a tool (e.g. Bash("rm temp.txt"))
↓
Gate 1: Permission mode check
├── bypassPermissions? → Execute directly, skip all checks
└── Other modes → Continue
↓
Gate 2: Rule matching
├── Matching allow rule? → Auto-execute
├── Matching deny rule? → Reject outright, return error to Claude
└── No matching rule → Continue
↓
Gate 3: Hook check (see Section V)
├── PreToolUse hook returns block? → Reject
└── Passes → Continue
↓
Gate 4: Tool's own checkPermissions()
├── Tool judges it dangerous? → Show confirmation dialog
└── Safe → Execute
↓
Execute tool
↓
PostToolUse hook runs (post-execution processing)
When a confirmation dialog appears, the prompt message shown to the user is generated by createPermissionRequestMessage(), which accurately states which rule requires confirmation or which Hook triggered the interception.