Dev.to Security 🔐 Cybersecurity 👁 0 📖 7 min read

What "Don't Ask Again" Saves in Claude Code, and How to Audit It

You're deep in a Claude Code session, the same permission prompt shows up for the fifth time, and you pick "Yes, and don't ask again". It's the right call most of the time. But that click doesn't just silence one prompt.

You're deep in a Claude Code session, the same permission prompt shows up for the fifth time, and you pick "Yes, and don't ask again". It's the right call most of the time. But that click doesn't just silence one prompt. For some tools it writes a rule to a file, and that rule keeps working in every future session in that repository.

After a few weeks, that file is a list of things Claude Code may do without asking you, and you didn't write any of it on purpose. This article covers what the click actually saves, where it goes, and a short audit to run before the list gets out of hand. Everything about Claude Code's behavior here comes from Anthropic's official permissions and settings docs.

What the click saves, by tool

The docs list what "Yes, and don't ask again" means for each kind of tool:

Tool type Asks by default? "Don't ask again" lasts
Bash commands Yes, except a built-in set of read-only commands Permanently, per repository and command
File edits and writes Yes Until the session ends
WebFetch Yes, except some preapproved documentation domains Permanently, per repository and domain
WebSearch Yes Permanently, per repository
File reads, Grep No, inside your working directories Not applicable

So file-edit approvals disappear when you close the session, but shell commands, fetch domains and web search stick.

The prompt also tells you what it will save. The docs' example shows a Bash prompt for npm test offering "Yes, and don't ask again for: npm test *". That trailing * matters: the saved rule covers npm test with any arguments, not only the exact command you just saw.

Where it goes

Permanent approvals are saved as allow rules in .claude/settings.local.json at the root of the git repository. A few details from the docs that are easy to miss:

  • It covers the whole repository. Start Claude Code in a subdirectory and the rule still lands at the repo root and applies everywhere in the repo, including worktrees, which resolve to the main checkout.
  • It stays out of git. The first time Claude Code writes the file, it adds **/.claude/settings.local.json to your global git excludes. Nobody reviews it in a pull request.
  • It skips the trust step. Allow rules in the committed .claude/settings.json wait until you accept the workspace trust dialog. Your local file is treated as yours, so its allow rules apply right away while it stays untracked.
  • Compound commands split. Approving git status && npm test saves a rule for npm test alone, and up to 5 rules can be saved from a single compound command.

None of this is a flaw. It's exactly what you want for npm test. It just means the file deserves a look now and then.

The audit: three steps

1. Look at what's there

Run /permissions inside Claude Code. The dialog lists every permission rule and the settings file it comes from, so you see local, project and user rules together. You can add or remove rules from the same dialog.

Or open the file directly. Here is an example of what a local file might look like after a few weeks (an illustrative file, not from a real project):

{
  "permissions": {
    "allow": [
      "Bash(npm test *)",
      "Bash(npm run lint)",
      "Bash(git *)",
      "Bash(npx *)",
      "Bash(docker exec *)",
      "WebFetch(domain:docs.python.org)",
      "WebSearch"
    ]
  }
}

2. Flag the rules that allow more than you meant

Two shapes deserve attention.

A wildcard right after the program name. The docs are explicit: everything before the first * is what limits the rule. Bash(git log *) allows only git log commands. Bash(git *) allows every git command, including git push. If you meant "let it read history", the narrower rule says so.

Environment runners. Claude Code strips a small fixed set of wrappers before matching (timeout, time, nice, nohup, stdbuf, plus a few shell builtins), but runners like npx, docker exec, devbox run, mise exec and direnv exec are not on that list. Because they execute their arguments as a command, the docs warn that Bash(devbox run *) also matches devbox run rm -rf .. The same logic applies to Bash(npx *) and Bash(docker exec *). The recommended fix is one specific rule per inner command, such as Bash(devbox run npm test).

If you have several repositories, a tiny script helps. This is my own sketch, not an official tool. It reads the allow list with jq and labels each rule:

#!/usr/bin/env bash
# Flag allow rules worth a second look in a Claude Code settings file.
f="${1:-.claude/settings.local.json}"
jq -r '.permissions.allow[]?' "$f" | while IFS= read -r rule; do
  if [[ "$rule" == "Bash" || "$rule" == "Bash(*)" ]]; then
    echo "ALL      $rule"
  elif [[ "$rule" =~ ^Bash\((npx|docker\ exec|devbox\ run|mise\ exec|direnv\ exec)\  ]]; then
    echo "RUNNER   $rule"
  elif [[ "$rule" =~ ^Bash\([^\ ]+(\ \*|:\*)\)$ ]]; then
    echo "BROAD    $rule"
  else
    echo "ok       $rule"
  fi
done

Run against the example file above (bash 5.2, jq 1.7), it prints:

ok       Bash(npm test *)
ok       Bash(npm run lint)
BROAD    Bash(git *)
RUNNER   Bash(npx *)
RUNNER   Bash(docker exec *)
ok       WebFetch(domain:docs.python.org)
ok       WebSearch

The script only knows the patterns you give it, so treat "ok" as "not flagged", not "safe".

3. Trim, then add guardrails

  • Narrow the broad rules. Replace Bash(git *) with the subcommands you actually approve, like Bash(git log *) and Bash(git diff *).
  • Replace runner wildcards with one exact rule per inner command.
  • Add ask rules for the commands you always want to see. Rules are evaluated deny, then ask, then allow, and the first match wins. Specificity doesn't change the order, so an ask rule like Bash(git push *) still prompts even if some broader allow rule also matches.
  • Add deny rules for secrets. Read(./.env) or Read(./secrets/**) blocks Claude's file tools from those paths, and a Read deny also blocks Edit and Write on the same path.

Put the ask and deny rules your whole team needs in the committed .claude/settings.json. Deny and ask rules only restrict, so they don't wait for workspace trust. A deny at any level blocks an allow at any other level.

Know where rules stop

Two limits from the docs are worth keeping in mind while you trim.

Bash rules match command text, not the program. A deny rule Bash(curl *) stops curl https://example.com but not /usr/bin/curl https://example.com or sh -c 'curl …'. Likewise, Read deny rules cover Claude's file tools and the file commands Claude Code recognizes in Bash, like cat or head, but not a Python or Node script that opens the file itself. When a restriction must hold, the docs point to sandboxing for filesystem and network isolation, or a PreToolUse hook that inspects the full command.

Rules are enforced by Claude Code, not by the model. Writing "never push" in CLAUDE.md shapes what Claude tries, but it doesn't change what Claude Code allows. Only permission rules, modes and hooks do that.

One more thing that confuses people: if you chose "don't ask again" and still get prompted, the settings docs explain why. Your choice saved an allow rule to your local file, and that allow rule doesn't outrank an ask rule from a project or managed settings file.

Quick checklist

  • [ ] Run /permissions once a week, or after a long session full of prompts
  • [ ] Read the "don't ask again for:" line before choosing it, especially the trailing *
  • [ ] No Bash(<program> *) rules for programs with dangerous subcommands
  • [ ] No wildcard rules on npx, docker exec or other runners
  • [ ] ask rules for pushes, deploys and anything you always want to see
  • [ ] deny rules for .env and secret folders, committed for the team
  • [ ] Sandboxing or a hook where a rule must actually hold
  • [ ] Nothing important enforced only by a line in CLAUDE.md

Where to go next

If you came to Claude Code from Codex, I covered permission basics alongside six other day-one settings in Coming to Claude Code from Codex? 7 Things to Set Up on Day One.

For the full picture, Claude Code: The Complete Guide is a 45-page guide with 22 chapters: when to use Claude Code and when to use Cursor, installation on macOS, Linux and Windows via WSL2, the workflows where it earns its place, three annotated sessions, cost management, headless mode and CI, and a chapter on team workflow and security. If you'd rather start small, the free Claude Code Quick-Start Cheat Sheet covers setup, essential commands and the Cursor vs Claude Code decision in 5 pages.

This article was written with the assistance of AI and reviewed by the author. Claude Code behavior is taken from Anthropic's official permissions and settings documentation as of 11 November 2026; the audit script is the author's own sketch and was run only on the example file shown. PromptMaster guides are independent and not affiliated with or endorsed by Anthropic.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.