[FEATURE] Show the permission rule that will be saved, verbatim, in the approval prompt

Status Open
Reported on v2.1.232
Maintainer reply None cached
Activity 0 comments · opened Aug 14, 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

When I approve a Bash command with "don't ask again", Claude Code writes a pattern into settings.json — but the approval prompt only shows a human-readable sentence. I never see the pattern. The gap between "the command I just looked at" and "the rule that will match forever after" is invisible at the only moment I can act on it.

Auditing my own project settings recently, I found these standing allow rules:

"Bash(rm -rf *)"        // unconditional recursive force-delete, any argument
"Bash(python -c ' *)"   // arbitrary code execution — a strict superset of the above
"Bash(powershell.exe *)"

I could not reconstruct which approval produced each of them, and I am not claiming a specific dialog generated a specific rule — I did not verify that causally. The narrower point is what matters:

  • Rules of this breadth can end up in settings.
  • Nothing in the approval flow shows breadth before the click.
  • Nothing in /permissions distinguishes them afterBash(rm -rf *) and Bash(git diff *) render identically.

Bash(python -c ' *) is the one that worries me most: it grants arbitrary code execution, but reads like a narrow, tool-specific rule. Someone scanning their allow-list for dangerous entries would stop at rm -rf and never flag it.

This is a safety property rather than a convenience one — an over-broad rule is silent, permanent, and only discovered by manually reading the JSON.

Proposed Solution

Show the exact rule text that will be written to settings, inline in the approval prompt, next to the "don't ask again" option:

  Run shell command
  $ rm -rf ./build

  [y] Yes, once
  [a] Yes, don't ask again    → will save:  Bash(rm -rf *)
  [n] No

The single line will save: Bash(rm -rf *) is the whole ask. It costs one line of output and lets me notice that a one-off cleanup is about to become an unconditional grant — which is exactly the moment I can still choose "yes, once" instead.

Same string should be shown when the rule is created any other way (e.g. the /permissions add flow), so what I read is always the thing that gets matched.

Alternative Solutions

Things I actually do today, none of which work well:

  • Read settings.json / .claude/settings.local.json by hand afterwards. This is how I found Bash(rm -rf *) — weeks after the fact, by accident.
  • Always choose "yes, once" and never persist anything. Safe, but then every command re-prompts and the feature stops being useful.
  • Pre-write the allow-list by hand and never use the interactive approval. Works, but requires knowing the pattern syntax up front, and the prompts still appear for anything not predicted.

Adjacent changes I considered proposing instead (deliberately left out to keep this a single request, but they compose well with it):

  • Make approval-list rows distinguishable — I recently had a /permissions list where four separate rows all read Run shell command, though one was a local find and another wrote a file into a container on a remote host. Showing the saved rule would incidentally fix this, since the patterns differ.
  • Warn when a wildcard lands on a destructive verb (rm, dd, mkfs, chmod -R, or interpreter escapes like python -c / node -e / sh -c). This needs a maintained list and is more debatable, which is why I'm not asking for it here.

Priority

High - Significant impact on productivity

Feature Category

Configuration and settings

Use Case Example

  1. I ask Claude to clean a build directory. It proposes rm -rf ./build.
  2. The prompt shows Run shell command plus the command. Looks obviously fine, so I pick "don't ask again" — I expect to be approving build-directory cleanups.
  3. Today: nothing else is displayed. Bash(rm -rf *) is written to .claude/settings.local.json. Every future rm -rf with any argument is now pre-approved, in this project, permanently.
  4. With this feature: the prompt reads will save: Bash(rm -rf *). I see the argument was generalized away, pick "yes, once" instead, and move on.

Step 4 takes no extra time and no extra knowledge — the pattern is right there next to the choice it belongs to.

Additional Context

Related but distinct issues (checked before filing):

  • #83406 and #86151 report the opposite failure mode — suggested patterns being too narrow, causing repeat prompts. The two asks are in tension: any fix that widens generalization makes displaying the resulting pattern more important, not less. Shipping this one first would make that work safer to do.
  • #85023 asks for the requesting agent + reasoning in the prompt. Complementary; it does not cover the saved-pattern text.

Note on scope: this is a display-only change — no change to how patterns are generated, matched, or stored. That is deliberate: getting generalization "right" is a hard, contested problem, whereas showing the user what was generalized is cheap and helps regardless of which direction generalization moves.

Environment: Claude Code 2.1.232, Linux (WSL2), defaultMode: auto.

View original on GitHub ↗