Claude Code Permission Modes Explained: Default, Auto-Edit, Bypass, and When to Use Each
A complete guide to Claude Code permission modes: default, acceptEdits, and bypassPermissions. Learn how to configure allowed/denied tools, use settings.json for persistent rules, and choose the right mode for every workflow from daily development to CI/CD pipelines.
Claude Code is not just a chat window. It can read and write files, run arbitrary bash commands, call external APIs, and spawn sub-agents. That power is exactly what makes it useful โ and exactly why the permission system exists.
Permission modes control which actions require your explicit approval before Claude executes them. Get the mode wrong and you either spend your day clicking "yes" on trivial edits, or you hand an AI agent unrestricted shell access to a machine with production credentials. Neither outcome is great.
This guide covers every mode, every flag, and the five real-world scenarios where each configuration makes the most sense.
Why Permissions Matter
Every Claude Code session can potentially:
Read source files, config files, .env files, and secrets
Write or overwrite any file the current user can access
Install packages, change git history, or trigger deployments
The permission system sits between Claude's intent and your machine. It is the difference between Claude suggesting a change and Claude making that change unilaterally.
The --permission-mode Flag
The primary entry point is the --permission-mode flag, which sets the approval behavior for an entire session:
bash
claude --permission-mode default # ask before bash + significant writes
claude --permission-mode acceptEdits # auto-approve file edits, ask for bash
claude --permission-mode bypassPermissions # skip all checks (danger zone)
Each mode is a different trade-off between safety and speed. Here is the full comparison:
Mode
File Reads
File Writes / Edits
Bash Commands
Use Case
default
Auto
Asks
Asks
New projects, unfamiliar codebases, production machines
acceptEdits
Auto
Auto
Asks
Trusted projects, daily development
bypassPermissions
Auto
Auto
Auto
Sandboxed CI/CD only
Mode 1: default
The default mode is what Claude Code uses when you do not specify anything. Claude will auto-approve read operations (it needs to read code to help you), but will ask for confirmation before:
Running any bash or shell command
Writing or editing files beyond what you explicitly approved in the current turn
bash
claude --permission-mode default
# or simply:
claude
When to use it: Any time you are working in an unfamiliar codebase, on a shared machine, or in a context where a wrong command could have irreversible side effects. This is the correct mode for exploring open-source repos, running on staging/production machines, or during security-sensitive work.
What it feels like: You see a prompt for every bash execution. For large refactors this can feel slow, but you retain complete situational awareness of every action.
Mode 2: acceptEdits
acceptEdits is the sweet spot for most day-to-day development. File operations โ Read, Edit, Write โ are auto-approved without interruption. Bash commands still require explicit approval.
bash
claude --permission-mode acceptEdits
This mode trusts that you have already reviewed the project enough that Claude editing a TypeScript file is low risk. But you still hold the gate on anything that touches the system: package installs, git operations, running tests, database commands.
When to use it: Your own projects, repos you know well, or any session focused on writing code rather than running it. The productivity gain over default is significant on file-heavy tasks.
What it feels like: Edits flow continuously without interruption. Bash prompts appear only when Claude needs to execute something, keeping you in the loop on side effects while removing friction from pure coding.
This mode disables all permission checks. Claude can read, write, and execute anything without asking. It exists specifically for automated pipelines where there is no human in the loop to approve prompts.
bash
# Via permission-mode flag
claude --permission-mode bypassPermissions
# Via the legacy flag (identical behavior)
claude --dangerously-skip-permissions
The word "dangerously" is in the flag name for a reason. Running bypass mode on any machine that has:
Internet access
Cloud provider credentials (AWS, GCP, Azure)
API keys for payment processors or data services
SSH keys or GPG keys
Database connection strings
...is a serious security risk. A single prompt injection in the codebase Claude is reading could trigger arbitrary command execution with no gate.
When to use it: Inside a fully sandboxed Docker container in a CI/CD pipeline that has no internet egress and no sensitive credentials mounted. The container should be ephemeral and discarded after the run.
When never to use it: Developer laptops, production servers, shared machines, or any environment where a compromised output could reach real systems.
--allow-dangerously-skip-permissions
This related flag makes bypass available as an option in a script without enabling it by default. It is designed for wrapper scripts that need to optionally pass through bypass behavior based on environment variables:
bash
# The script can enable bypass when the CI flag is present
claude --allow-dangerously-skip-permissions "$@"
Configuring Allowed and Denied Tools
Beyond the top-level mode, you can whitelist and blacklist specific tools or tool patterns for fine-grained control.
CLI Flags
bash
# Allow only git commands, npm, and file edits
claude --allowed-tools "Bash(git *) Bash(npm *) Edit Write Read"# Allow everything except dangerous destructive bash commands
claude --disallowed-tools "Bash(rm *) Bash(curl *) Bash(wget *)"# Combine both for a precise allow-list with exceptions
claude --allowed-tools "Bash(git *) Edit Write" \
--disallowed-tools "Bash(git push *)"
Tool patterns use glob-style matching. Bash(git *) permits all git subcommands. Bash(rm *) blocks all rm invocations regardless of arguments.
settings.json Persistent Configuration
CLI flags only apply to a single session. For persistent rules that apply every time Claude Code runs in a project, add a permissions block to .claude/settings.json:
This file is checked into your repository, so the rules travel with the codebase. Every developer who runs Claude Code on the project inherits the same guardrails automatically โ no per-session flags required.
Key distinction:deny rules always override allow rules. If a tool matches both lists, it will be blocked.
--safe-mode: The Debugging Baseline
--safe-mode is a separate concern from permission levels. It launches Claude with all customizations completely disabled:
CLAUDE.md project instructions are ignored
Hooks (pre/post-tool hooks) do not run
Plugins are not loaded
MCP (Model Context Protocol) servers are not started
bash
claude --safe-mode
When to use it: Diagnosing unexpected Claude behavior where you suspect a hook or CLAUDE.md instruction is interfering. It gives you a clean baseline session with none of the project-level overrides in effect โ useful for audits or for reproducing issues before filing a bug report.
Safe mode does not change the permission level. You still need to set --permission-mode if you want non-default approval behavior.
Per-Session vs Persistent Permissions
Mechanism
Scope
How to Set
--permission-mode flag
Current session only
CLI flag at startup
--allowed-tools flag
Current session only
CLI flag at startup
--disallowed-tools flag
Current session only
CLI flag at startup
.claude/settings.json
All sessions in the project
Committed file in repo
~/.claude/settings.json
All sessions for the user
User-level config file
For team projects, committing .claude/settings.json is strongly recommended. It ensures consistent permissions across all contributors and CI runners without requiring everyone to remember the right flags.
Real-World Scenarios
Scenario 1: Daily Development on Your Own Project
Recommended mode:acceptEdits
bash
claude --permission-mode acceptEdits
You know the codebase. File edits are low risk. Bash prompts keep you in control of installs, tests, and git operations. This is the fastest mode that still keeps you meaningfully in the loop.
Scenario 2: Exploring an Unfamiliar Codebase
Recommended mode:default
bash
claude --permission-mode default
When you do not know what the bash commands in a Makefile do, or where the database migration scripts live, you want every execution to require your approval. The extra prompts are not friction โ they are information.
Scenario 3: CI/CD Automated Pipeline in a Container
Recommended mode:bypassPermissions
bash
# Inside a sandboxed Docker container with no internet egress
claude --permission-mode bypassPermissions \
--print"Run the test suite and fix any failing tests"
The container is ephemeral, has no sensitive credentials, and no human is available to approve prompts. Bypass is the only viable option. Combine with explicit --disallowed-tools rules in settings.json as a secondary defense layer even in CI.
Scenario 4: Running on a Shared or Production Machine
On a shared machine, default mode keeps every action visible. The deny list adds a hard block on the most dangerous commands regardless of what Claude is asked to do โ belt and suspenders.
Scenario 5: Quick One-Off Script
Recommended mode:--print (non-interactive)
bash
claude --print"Generate a bash script to rename all .jpeg files to .jpg in the current directory"
--print mode outputs Claude's response to stdout and exits immediately. No interactive session, no permission prompts, no file modifications โ Claude generates the text and you decide what to do with it. This is the lowest-risk mode for exploratory or generative tasks.
Security Best Practices
Never use bypass on a machine with internet access. The risk vector is prompt injection: if Claude reads a file that contains adversarial instructions (a malicious dependency README, a crafted code comment, a poisoned config file), those instructions could trigger shell commands with no approval gate.
Commit your settings.json. Persistent deny rules are far more reliable than remembering the right CLI flags. A committed settings.json is auditable, reviewable, and consistent across environments.
Prefer acceptEdits over bypassPermissions wherever possible. Even in local automation scripts, keeping the bash gate active prevents an entire class of accidents.
Use --safe-mode before filing bug reports. Isolating Claude from all hooks and instructions makes it far easier to determine whether unexpected behavior is a product bug or a configuration issue.
Scope your allow-list tightly in CI. Instead of full bypassPermissions, consider using default + a narrow allow list in settings.json even in automation. This prevents the pipeline from executing commands outside the expected set even if something goes wrong.
Permission flag names and settings.json schema may evolve across Claude Code releases. Always verify current behavior against the official Claude Code documentation for the version you are running.