docsfoundations4 min read

Permissions: Stop Clicking 'Allow' on Everything

Permission fatigue is the number two complaint about Claude Code. Five minutes of config fixes it permanently. Here's exactly what to set and why.

Five clicks before anything actually happens.

That's what default Claude Code feels like. You ask it to fix a test. It wants to read the file. Allow. Edit the file. Allow. Run the test. Allow. Check the output. Allow. It's like having an assistant who asks permission before touching anything in the office.

The fix takes five minutes. You configure it once. Then it just works.

With permission rules set, none of those steps stopped to ask. On a default setup, each one waits for your approval first.

Setting up permission rules

The config lives in settings.json. Two places to put it:

Project-level (.claude/settings.json in your repo): gets checked into git, shared with your team. Good for project-specific tools like your test runner or lint commands.

User-level (~/.claude/settings.json): your personal defaults across every project you work on.

Here's a solid starting config:

json
{
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "Bash(npm test *)",
      "Bash(npm run lint *)",
      "Bash(npx tsc *)",
      "Bash(git status *)",
      "Bash(git diff *)",
      "Bash(git log *)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push --force *)",
      "Bash(git reset --hard *)"
    ]
  }
}

Read operations are always safe. Your test and lint commands are safe. Anything that deletes files or pushes to remote: always keep human review on those.

Mind the space before the *. Bash(ls *) matches ls -la but not lsof. Bash(ls*) with no space matches both.

When rules overlap, deny wins, then ask, then allow. A deny rule like Bash(rm -rf *) blocks the command even if a broader allow rule also matches it.

There's a third place for rules too: .claude/settings.local.json applies to one project and stays on your machine, out of git.

The /permissions Command

Mid-session and tired of clicking? Type /permissions to manage it on the fly.

It opens your allow, ask and deny rules, where you can add or remove a rule without editing settings.json by hand.

What to Auto-Accept vs What to Always Review

Always auto-accept:

  • Read: reading files literally never changes anything
  • Glob: searching file names, harmless
  • Grep: searching file contents, harmless
  • Bash(git status *), Bash(git diff *), Bash(git log *): read-only git commands

Auto-accept with patterns (mostly safe):

  • Bash(npm test *): running your tests
  • Bash(npm run lint *): running linters
  • Bash(npx tsc *): type checking
  • Edit: once you've used Claude Code for a week and trust the edit quality, most people add this

Always review:

  • Bash(rm *): file deletion
  • Bash(git push *): pushing to remote
  • Bash(git checkout *): branch switching
  • Bash(git reset *): resetting changes
  • Bash(npm publish *): publishing packages
  • Bash(curl *): making network requests
  • Anything touching production

The Progressive Trust Approach

Don't try to configure everything perfectly on day one. You don't yet know what Claude Code actually does in your workflow.

Week 1: Auto-accept reads only. Watch what it actually does before each operation.

Week 2: Add test and lint commands to auto-accept. You've seen enough by now to know it's not running weird shell commands.

Week 3: Add Edit if you're confident in the edit quality. Most people get here.

Week 4+: You're reviewing only destructive operations and network calls. That's the sweet spot: 90% of operations flow without interruption, 10% get a human eye where it matters.

json
{
  "permissions": {
    "allow": ["Read", "Glob", "Grep", "Edit", "Bash(npm test *)", "Bash(npm run lint *)"],
    "ask": ["Bash(git push *)", "Bash(rm *)", "Bash(curl *)", "WebFetch"]
  }
}

Auto mode, plan mode and headless runs

Rules decide single tool calls. The permission mode decides what happens when no rule matches. Five recent changes are worth knowing:

  • Headless runs start in Manual mode. Since v2.1.302, every claude -p and Agent SDK run with no permission mode set starts in Manual mode, which settings and SDK options call default. Before that, runs on a third-party provider or with telemetry off started in auto. In Manual mode nobody is there to click Allow, so a call that needs approval is denied unless an allow rule, a hook, a canUseTool callback or --permission-prompt-tool approves it. For a script or cron job, pass --allowedTools "Bash(npm test)" for the calls you expect, or --permission-mode auto to let the classifier decide.
  • You can pick the classifier model. CLAUDE_CODE_AUTO_MODE_MODEL (v2.1.302) sets the model the client-side auto mode classifier uses. It doesn't change the model for server-side auto mode.
  • Long conversations no longer lock auto mode. With the server-side classifier, a conversation too long for the safety check is now compacted (v2.1.302). Before, every checked tool call was denied.
  • Plan mode warns you once when it won't ask. If bypass permissions is available, plan mode won't ask before most edits or commands, and since v2.1.299 Claude Code tells you so the first time.
  • Bypass mode still stops rm on critical paths, unless you switch that off. Even in bypassPermissions mode, rm and rmdir aimed at a critical path such as your home folder get a prompt, and no allow rule or PreToolUse hook can approve them. In the desktop app and VS Code the command is denied at once with a hint to rewrite it (v2.1.309). Since v2.1.311 you can turn the prompt off by starting Claude Code with CLAUDE_CODE_EVEN_MORE_DANGEROUSLY_SKIP_PERMISSIONS=1 set in your shell. It only works from the launch environment: Claude Code ignores it in a settings file's env block, and in the desktop app or the VS Code chat panel it has no effect. With it on, a command like rm -rf ~ can run without asking, so keep it to throwaway containers and VMs.

One More Thing: The Accept Button

When a permission prompt does appear, you've got more options than just yes:

  • Yes: allow this once
  • Yes, and don't ask again: allow it and save a rule, so Claude Code stops asking for this command in this project
  • No: deny this request
  • Escape: cancel the current operation

"Don't ask again" is underused. For a shell command, Claude Code writes the rule to .claude/settings.local.json, so you build your allow list just by working. Check that file now and then to see what you've approved.

New guides, when they ship

One email, roughly weekly. CLAUDE.md templates, workflows I actually use, and the cut-for-length stuff that does not make the public guides. One-click unsubscribe.

Or read Product Field Notes, the Substack