Understanding the Permission Model
Understanding the Permission Model
Claude Code has the ability to read your files, write new code, and execute terminal commands. That is powerful -- and it means you need a way to stay in control. The permission model is how Claude Code balances capability with safety, ensuring it never takes an action you have not approved.
In this lesson, you will learn how the permission system works, how to configure it for your workflow, and best practices for using it effectively.
What You'll Learn
- Why the permission model exists and what problems it solves
- The three permission modes and when to use each
- Which tools Claude Code has and what each one does
- How the approval flow works in practice
- The "always allow" option and session-level permissions
- Configuring persistent permissions in
.claude/settings.json - Best practices for permission management
Why Permissions Matter
Claude Code is not a read-only tool. It can:
- Write and edit files anywhere in your project directory
- Delete files if asked to clean up or refactor
- Run shell commands including build scripts, test suites, and arbitrary terminal commands
- Execute git operations like committing, branching, and pushing
- Install packages via npm, pip, or other package managers
Without a permission system, a single misunderstood prompt could lead to unwanted file modifications, accidental deletions, or running commands you did not intend. The permission model ensures that you see and approve every significant action before it happens.
Think of it like sudo in Unix systems. Having root access is powerful, but you want to be explicit about when you use it. Claude Code's permission model gives you that same explicitness.
The Three Permission Modes
Claude Code operates with three primary approaches to permissions, and you can configure them at different levels.
Ask Mode (Default)
In the default mode, Claude Code asks for your approval before taking any action that modifies your system. This includes writing files, editing existing files, and running shell commands.
When Claude Code wants to take an action, you will see a prompt like:
Claude wants to edit file: src/utils/helpers.ts
function formatDate(date: Date): string {
- return date.toString();
+ return date.toISOString().split('T')[0];
}
Allow this edit? (y/n)
You review the proposed change and type y to approve or n to reject.
This mode is the safest and is recommended when:
- You are first getting started with Claude Code
- You are working on critical production code
- You want to understand every change being made
- You are using Claude Code on an unfamiliar codebase
Auto-Accept Mode
You can launch Claude Code with the --dangerously-skip-permissions flag to skip all permission prompts:
claude --dangerously-skip-permissions
In this mode, Claude Code executes all actions without asking. The flag name is intentionally dramatic -- it is a reminder that you are giving Claude Code full autonomy.
Use this mode only when:
- You are working in a sandboxed environment (Docker container, VM, disposable branch)
- You are running automated tasks where human approval is not possible
- You are working on throwaway code where mistakes are easily reversed
- You fully trust the task and have a clear, unambiguous prompt
Do not use this mode when:
- You are working on production code
- You are on the main branch of an important repository
- You are giving Claude Code broad, open-ended instructions
- You are still learning how Claude Code behaves
Selective Permissions
The most practical approach for experienced users is selective permissions -- allowing certain safe operations automatically while requiring approval for others. This is configured through the settings file, which we will cover later in this lesson.
For example, you might allow file reads automatically (they cannot change anything) but require approval for file writes and command execution.
Tool-Level Permissions
Claude Code uses a set of internal tools to interact with your system. Understanding these tools helps you make informed decisions about what to allow.
Read Tool
What it does: Reads the contents of files in your project.
Risk level: Low. Reading files does not modify anything.
Claude is reading: src/components/Header.tsx
Many users configure this to be automatically allowed since it has no side effects.
Write Tool
What it does: Creates new files or completely replaces existing file contents.
Risk level: Medium. Creates or overwrites files. Claude Code shows you the full content before writing.
Claude wants to create: src/utils/validation.ts
[Full file contents shown here]
Allow? (y/n)
Edit Tool
What it does: Makes targeted edits to existing files, showing a diff of the changes.
Risk level: Medium. Modifies existing files, but you see exactly what changes are proposed.
Claude wants to edit: src/app/api/users/route.ts
export async function GET(request: Request) {
+ const session = await getSession();
+ if (!session) {
+ return Response.json({ error: 'Unauthorized' }, { status: 401 });
+ }
+
const users = await db.users.findMany();
return Response.json(users);
}
Allow? (y/n)
Bash Tool
What it does: Executes shell commands in your terminal.
Risk level: High. Shell commands can do virtually anything -- install packages, delete files, make network requests, and more.
Claude wants to run: npm test -- --coverage
Allow? (y/n)
Some commands are obviously safe (like npm test or ls), while others could be dangerous. Claude Code shows you the exact command before running it.
Glob and Grep Tools
What they do: Search for files by name patterns (glob) or search file contents (grep).
Risk level: Low. These are read-only operations used to find relevant files in your codebase.
How the Approval Flow Works
Let us trace through a complete example to see how permissions work in practice.
Suppose you ask:
> Add input validation to the register endpoint
Here is what happens:
Step 1: Claude Code reads relevant files (if auto-allowed, this happens silently):
Reading: src/app/api/auth/register/route.ts
Reading: src/lib/validation.ts
Reading: src/types/user.ts
Step 2: Claude Code proposes an edit:
Claude wants to edit: src/app/api/auth/register/route.ts
export async function POST(request: Request) {
const body = await request.json();
+
+ const validation = validateRegistration(body);
+ if (!validation.success) {
+ return Response.json(
+ { errors: validation.errors },
+ { status: 400 }
+ );
+ }
+
const user = await createUser(body);
You review and type y.
Step 3: Claude Code proposes adding a validation function:
Claude wants to edit: src/lib/validation.ts
+export function validateRegistration(data: unknown) {
+ const errors: string[] = [];
+ // ... validation logic
+}
You review and type y.
Step 4: Claude Code wants to run the tests:
Claude wants to run: npm test -- auth
Allow? (y/n)
You type y. The tests run and Claude Code reports the results.
At every step, you saw exactly what Claude Code wanted to do and had the opportunity to reject it. This is the core of the permission model.
The "Always Allow" Option
Typing y for every single action can get tedious, especially for safe operations. Claude Code offers an "always allow" option for specific tools.
When Claude Code asks for permission, you can respond with more than just y or n:
y-- Allow this one timen-- Deny this one timea-- Always allow this tool for the rest of the session
For example, if Claude Code asks to run npm test:
Claude wants to run: npm test
Allow? (y/n/a)
If you type a, Claude Code will be allowed to run bash commands for the rest of the current session without asking. When you exit and restart Claude Code, permissions reset to defaults.
Session vs Persistent Permissions
It is important to understand the distinction:
- Session permissions (set with
aduring a conversation) last only until you exit Claude Code - Persistent permissions (set in
.claude/settings.json) apply every time you start Claude Code
Session permissions are convenient for focused work sessions where you trust the current task. Persistent permissions are for operations you always want to allow.
Configuring Persistent Permissions
For a more permanent configuration, you can create a .claude/settings.json file in your project root or in your home directory.
Project-Level Settings
Create .claude/settings.json in your project root for project-specific permissions:
mkdir -p .claude
The settings file uses a JSON format:
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep"
],
"deny": []
}
}
This configuration automatically allows all read operations while requiring approval for writes and command execution.
User-Level Settings
You can also set permissions globally in your home directory at ~/.claude/settings.json. These apply to all projects unless overridden by project-level settings.
Allowing Specific Commands
You can be more granular with bash command permissions by specifying patterns:
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Bash(npm test*)",
"Bash(npm run lint*)",
"Bash(npx tsc*)"
],
"deny": [
"Bash(rm -rf*)",
"Bash(sudo*)"
]
}
}
This configuration:
- Automatically allows reading files and running searches
- Automatically allows npm test, lint, and TypeScript type-checking commands
- Explicitly blocks
rm -rfandsudocommands - Requires approval for all other bash commands and all file writes
Common Permission Configurations
Here are some practical configurations for different scenarios:
Conservative (recommended for beginners):
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep"
],
"deny": []
}
}
Moderate (good for experienced users):
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Edit",
"Write",
"Bash(npm test*)",
"Bash(npm run lint*)",
"Bash(npm run build*)",
"Bash(npx tsc*)",
"Bash(git status*)",
"Bash(git diff*)",
"Bash(git log*)"
],
"deny": [
"Bash(rm -rf*)",
"Bash(sudo*)",
"Bash(git push*)"
]
}
}
Permissive (for sandboxed environments):
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Edit",
"Write",
"Bash"
],
"deny": []
}
}
Allowed Tools vs Dangerous Operations
Not all operations carry the same risk. Here is a practical breakdown.
Generally Safe to Auto-Allow
These operations do not modify your project:
- Read -- Reading file contents
- Glob -- Finding files by name pattern
- Grep -- Searching file contents
- Bash(git status) -- Checking repository status
- Bash(git diff) -- Viewing changes
- Bash(git log) -- Reading commit history
Moderate Risk -- Review but Usually Safe
These modify your project but in controlled ways:
- Edit -- Targeted file edits (you can see the diff)
- Write -- Creating new files (review the contents)
- Bash(npm test*) -- Running tests
- Bash(npm run lint*) -- Running linters
- Bash(npx tsc*) -- Type checking
Higher Risk -- Always Review
These can have significant side effects:
- Bash(npm install*) -- Modifies node_modules and package.json
- Bash(git commit*) -- Creates permanent history entries
- Bash(git push*) -- Sends changes to remote repositories
- Bash(rm*) -- Deletes files
- Arbitrary bash commands -- Could do anything
Best Practices
1. Start Restrictive, Loosen as You Build Trust
When you first start using Claude Code, keep the default permission settings. Approve each action manually. As you develop an understanding of how Claude Code behaves and what kinds of commands it typically runs, gradually allow more operations automatically.
2. Use Project-Level Settings for Team Consistency
If your team uses Claude Code, commit a .claude/settings.json file to your repository. This ensures everyone has the same baseline permissions and prevents accidental misuse.
3. Always Deny Destructive Commands
Regardless of your experience level, consider always blocking commands like:
{
"permissions": {
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)",
"Bash(git push --force*)"
]
}
}
These commands have the potential for irreversible damage. It is better to run them manually when needed.
4. Review Diffs Carefully
When Claude Code proposes an edit, take a moment to read the diff. Look for:
- Unintended changes to unrelated code
- Hardcoded values that should be configuration
- Missing error handling
- Changes that do not match your project's conventions
5. Use Git as Your Safety Net
Always work in a git repository with your changes committed before starting a Claude Code session. This way, if Claude Code makes changes you do not like, you can easily revert:
# Before starting Claude Code, commit your current state
git add -A && git commit -m "checkpoint before claude code session"
# After Claude Code makes changes, if you want to undo:
git diff # Review what changed
git checkout -- . # Undo all changes
# Or selectively:
git checkout -- src/file.ts # Undo changes to specific file
6. Use Branches for Risky Work
When asking Claude Code to make large-scale changes, work on a branch:
git checkout -b refactor/update-auth
claude
# If things go well, merge the branch
# If not, delete it -- no harm done
How Permissions Interact with CLAUDE.md
In later lessons, you will learn about CLAUDE.md files that provide project-specific instructions to Claude Code. The permission model and CLAUDE.md work together:
CLAUDE.mdtells Claude Code what to do (coding conventions, architecture patterns, preferred tools).claude/settings.jsontells Claude Code what it is allowed to do (which tools it can use without asking)
They complement each other. CLAUDE.md guides Claude Code's decisions; permissions gate its actions.
Checking Your Current Permissions
You can review what permissions are currently active during a session:
> What permissions do you currently have? Which tools can you use without asking?
Claude Code will tell you which tools are available and which require approval. This is useful when you are not sure why Claude Code is or is not asking for permission on certain actions.
Summary
The permission model is what makes Claude Code safe to use on real projects. It ensures that you see and approve every significant action, from file edits to shell commands. The system is flexible -- you can be as restrictive or permissive as your situation requires.
Start with the defaults, approve actions manually as you learn, and gradually configure persistent permissions for operations you trust. Keep destructive commands blocked, use git as a safety net, and review diffs before approving edits.
With the permission model understood, you are ready to move on to the core workflows of Claude Code -- navigating codebases, writing features, and debugging.
Key Takeaways
- Claude Code's permission model ensures you approve every file modification and command execution
- The default "ask" mode requires manual approval for each action -- the safest option for beginners
- The
--dangerously-skip-permissionsflag auto-approves everything and should only be used in sandboxed environments - Tools have different risk levels: Read/Glob/Grep are safe; Edit/Write are moderate; Bash commands vary widely
- Type
aduring approval to allow a tool for the rest of the session - Configure persistent permissions in
.claude/settings.jsonat the project or user level - Use pattern matching like
Bash(npm test*)to allow specific commands while blocking others - Always deny destructive commands like
rm -rfandgit push --force - Use git branches and commits as a safety net alongside the permission system
Questionário
Discussion
Sign in to join the discussion.

