By default Claude Code asks before it edits a file or runs a command. That is safe, but approving every step gets tedious fast. Understanding Claude Code permission modes and permission rules lets you remove the noise without handing over the keys.
The permission modes
- Default: Claude asks the first time it needs to edit files or run most commands. Reading files is allowed without a prompt.
- Accept edits: file edits go through automatically, but shell commands still need approval.
- Plan mode: Claude can only read and research. It proposes a plan and waits for you to approve it before touching anything.
- Bypass permissions: no prompts at all. It is meant for isolated environments only.
Press Shift+Tab in the terminal to cycle through the modes during a session. You can also start in one directly:
claude --permission-mode plan
Newer releases add further modes, so check the permissions section of the current Claude Code docs for the full list.
Use plan mode for anything non-trivial
Plan mode is the most useful mode for real work. Ask for a change, let Claude read the code, and it produces a step-by-step plan. You can correct the approach, narrow the scope or reject it entirely before a single file changes. It is the cheapest way to catch a misunderstanding, and it suits unfamiliar codebases, refactors and risky migrations.
When you accept the plan, Claude leaves plan mode and starts the work. Review the plan like you would review a pull request description.
Allow, ask and deny rules
Modes are broad. Rules are precise. Permission rules live in your settings files and say which tools Claude may use without asking, which always prompt, and which are blocked.
// .claude/settings.json (shared with your team)
{
"permissions": {
"allow": [
"Bash(npm run test:*)",
"Bash(npm run lint)",
"Bash(git diff:*)",
"Bash(git status)"
],
"deny": [
"Read(./.env)",
"Read(./secrets/**)",
"Bash(rm -rf:*)",
"Bash(curl:*)"
]
}
}
Deny rules win over allow rules, so you can allow a broad set and still carve out exceptions. The :* suffix matches commands that start with that prefix. Rule syntax has changed over time, so confirm the exact format in the docs for your version.
Where the settings live
~/.claude/settings.json: personal rules that apply to every project..claude/settings.json: project rules you commit so the whole team shares them..claude/settings.local.json: your personal overrides for one project, normally git-ignored.
Inside a session, the /permissions command shows the active rules and lets you add or remove them, which is a quick way to build a list as you go.
A sensible starting setup
- Start sessions in plan mode for new or risky tasks.
- Allow your test, lint and read-only git commands so routine checks never interrupt you.
- Deny reads of
.env, key files and anything with credentials. - Block network tools and destructive commands unless a task truly needs them.
- Commit the project settings file so everyone gets the same guard rails.
Be careful with bypass mode
The bypass flag, --dangerously-skip-permissions, removes every confirmation. Only use it inside a container or disposable virtual machine with no access to secrets or production systems. An agent that can run arbitrary commands without asking can delete files, push code or leak data if it is misled by a malicious file or web page. For ordinary development, a well-tuned allow list gives you most of the speed with far less risk.
Spend ten minutes on your permission rules once and you will save yourself hundreds of approval clicks, while keeping control over the things that matter.

Leave a Reply
You must be logged in to post a comment.