What "Don't Ask Again" Saves in Claude Code, and How to Audit It A developer's audit of Claude Code's "Yes, and don't ask again" permission option shows that approvals for Bash commands, WebFetch domains and WebSearch persist permanently per repository, while file-edit approvals expire at session end. Those permanent rules are written as allow entries to .claude/settings.local.json, which is typically gitignored and unreviewed, and broad wildcard rules such as Bash(git *) or Bash(npx *) can match far more than intended, including destructive commands passed through environment runners. The writeup recommends auditing rules via the /permissions dialog or the file directly and replacing broad wildcards with one specific rule per inner command. 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 https://code.claude.com/docs/en/permissions and settings https://code.claude.com/docs/en/settings docs. 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. 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: /.claude/settings.local.json to your global git excludes. Nobody reviews it in a pull request. .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. 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. 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" } } 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: bash /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". Bash git with the subcommands you actually approve, like Bash git log and Bash git diff . ask rules for the commands you always want to see. Bash git push still prompts even if some broader allow rule also matches. 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. 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 https://code.claude.com/docs/en/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. /permissions once a week, or after a long session full of prompts Bash