Claude Code Learning Hub
中文 Mingyu's Library

Hub / Tips / E · Configuration & choosing tools

Permissions: from approving every step to uninterrupted flow

Clicking "yes" on every single command gets old fast — but jumping straight to allow-everything is dangerous. This tip lays out the officially supported path to progressively loosening permissions, and the lines you must not cross.

Claude Code's permission system has two layers: the permission mode sets the baseline, and allow/ask/deny rules provide fine-grained overrides. The right way to loosen up is to climb these two layers step by step — not to flip on bypassPermissions.

One-line answer

Answer Four progressive steps: build an allowlist in default mode via "Yes, don't ask again" → switch to acceptEdits to skip edit confirmations → move up to auto mode and let a classifier do background safety review; meanwhile use ask rules to keep a manual checkpoint on git push and deny rules to block sensitive files. Use bypassPermissions only inside an isolated container/VM — never day-to-day on your own machine.

Steps

  1. Start in default mode and let approvals settle into rules.OfficialDefault mode (called Manual in the UI) skips confirmation only for reads; Bash commands need approval on first use. When approving, pick "Yes, don't ask again" and the Bash rule is stored permanently in .claude/settings.local.json at the repo root, taking effect for future sessions across the whole repo (including subdirectories and worktrees); approving a compound command (like git status && npm test) saves it split into sub-commands. File-edit approvals last only until the session ends and are never persisted. After a day or two of use, your everyday commands have accumulated into a realistic allowlist.
  2. Tidy the rules with /permissions.Official/permissions lists every allow/ask/deny rule and its source file. Evaluation order is fixed: deny → ask → allow, first match wins, and specificity does not change the order (so a broad deny overrides a narrow allow). When hand-writing rules, mind the wildcard semantics: Bash(npm run *) matches commands starting with npm run; the space in Bash(ls *) is a word boundary — it matches ls -la but not lsof. To share with your team, move the rules into .claude/settings.json and commit it.
  3. Switch to acceptEdits and review after the fact.OfficialPress Shift+Tab in a session to cycle through modes. acceptEdits auto-accepts file edits inside the working directory plus common filesystem commands (mkdir, touch, mv, cp, sed, etc.); other Bash commands still prompt as usual. It fits the "let it edit, then review everything at once with git diff" workflow. To make it your default, put "permissions": {"defaultMode": "acceptEdits"} in ~/.claude/settings.json.
  4. Move up to auto mode: uninterrupted, but with a backstop.OfficialIn auto mode everything runs automatically while a separate classifier model reviews each action in the background, blocking high-risk operations by default — curl | bash, force pushes, production deploys, sending secrets out of the repo; boundaries you state in the conversation (like "don't push yet") also count as blocking signals. Two caveats: entering auto mode temporarily revokes broad allow rules that grant arbitrary code execution, such as Bash(*) (narrow rules like Bash(npm test) are kept); explicit ask rules still force a prompt. Auto mode requires your account to meet model and other conditions — if it doesn't, it simply won't appear in the Shift+Tab cycle. What each mode skips confirmation for:
    ModeNo confirmation needed forBest for
    default (Manual)Reads onlyGetting started, sensitive work
    acceptEditsReads + file edits + common filesystem commandsEdit freely, review via diff
    planReads (when auto is available, classifier-approved commands pass too)Exploring before touching anything
    autoEverything, with background classifier reviewLong tasks, fighting confirmation fatigue
    dontAskOnly pre-approved tools; everything else auto-deniedCI, locked-down script environments
    bypassPermissionsEverything, no reviewIsolated containers/VMs only
  5. Hold the safety line — what never to allow.OfficialThe explicit official rules: use bypassPermissions only in isolated environments (it even allows writes to protected paths like .git and .claude, and refuses to start under root/sudo); to stay uninterrupted while keeping a manual checkpoint, add ask rules on push-type actions — the official recipe is "ask": ["Bash(git push *)", "Bash(gh pr create *)"], which forces a prompt even in auto mode; deny sensitive files, e.g. Read(.env), Read(~/.ssh/**). Our takeTwo more practical rules: never allow any download-and-execute command (curl | bash); and remember that Bash prefix rules match the command string — a deny on Bash(rm *) won't stop /bin/rm or find -delete, so when you need a hard guarantee use a PreToolUse hook or the sandbox (see D3 Permission modes & the sandbox). Also remember: permissions are enforced by Claude Code, while "don't do X" written in CLAUDE.md is guidance, not a boundary.

Copy-paste prompt

Upgrade this project's permission setup from "confirm every step" to "fewer interruptions, firm boundaries":

1. Read the allow rules accumulated in .claude/settings.local.json, pick out the
   build/test/lint commands worth sharing with the team, and organize them into
   permissions.allow in .claude/settings.json;
2. Add "Bash(git push *)" and "Bash(gh pr create *)" to permissions.ask,
   keeping a manual checkpoint for pushes and PR creation;
3. Add permissions.deny rules for reading .env, secrets directories, and ~/.ssh;
4. Do not allow any deletion commands, download-and-execute commands (curl|bash),
   or commands that change system configuration;
5. When done, explain what each rule does, and tell me how the deny → ask → allow
   evaluation order affects this configuration.

Sources & last verified