Permissions & Security
Control what Claude can do — file access, tool permissions, and sandboxing.
Permission Modes
Claude Code has six permission modes. Shift + Tab cycles default → acceptEdits → plan by default; auto and bypassPermissions slot in after plan once enabled. dontAsk never appears in the cycle — set it explicitly via --permission-mode.
- default — Claude asks before file writes or shell commands. The starting mode.
- acceptEdits — File edits and common filesystem commands (
mkdir,touch,mv,cp,rm, ...) run without prompting. Other tools still prompt. - plan — Claude reads files and runs shell commands to explore, but won't edit your source. Permission prompts still apply the same as
defaultfor other tools. See Plan Mode. - auto — A separate classifier model reviews actions in the background. Requires Claude Code v2.1.83+, a supported model, and any required organization admin enablement. It is available by default on the Anthropic API; Bedrock, Vertex AI, and Microsoft Foundry require
CLAUDE_CODE_ENABLE_AUTO_MODE=1and currently support only Opus 4.7 or Opus 4.8. - dontAsk — Auto-deny anything not in your
permissions.allowlist. Use for locked-down CI. - bypassPermissions — All checks off. Only safe inside containers / VMs with limited blast radius.
You can start in a specific mode with the --permission-mode flag:
claude --permission-mode plan # exploratory, no edits
claude --permission-mode acceptEdits # skip file-edit prompts
claude --permission-mode auto # background classifier
claude --permission-mode dontAsk # locked-down CIFor fully unattended use (CI, scripts) without a classifier, pass --dangerously-skip-permissions — equivalent to --permission-mode bypassPermissions. Only use it in sandboxed environments where you control the inputs.
Configuring Allowed Tools
Fine-grained control lives in .claude/settings.json. The permissions object has allow, deny, and ask arrays:
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Bash(npm run lint)",
"Bash(npm test)",
"Bash(git status)",
"Bash(git diff)",
"Bash(git *)"
],
"deny": [
"Bash(rm -rf *)"
]
}
}deny always overrides allow. For Bash, you can scope to specific commands using glob syntax — Bash(npm test) allows only that exact command; Bash(git *) matches any git subcommand.
Use ask when an action is sometimes acceptable but should stay visible:
{
"permissions": {
"ask": ["Bash(npm install *)", "Edit"]
}
}Directory & File Restrictions
Restrict write access to specific directories using permissions.additionalDirectories or CLAUDE.md instructions:
## Constraints
- Never modify files outside src/ and tests/
- Never read or write .env, .env.local, or any credentials file
- Never run rm -rf or any destructive shell commandFor hard enforcement, use a PreToolUse hook that rejects writes outside your approved directories. CLAUDE.md instructions are best-effort; hooks are deterministic.
You can also expand the directories Claude is allowed to access (beyond the project root):
{
"permissions": {
"additionalDirectories": ["/shared/libs", "~/design-tokens"]
}
}Changes to additionalDirectories take effect immediately within a running session.
Claude Code also protects sensitive paths such as credentials and system files. Treat this as a backstop, not a replacement for explicit deny rules and hooks in high-risk repos.
Sandboxed Sessions
For maximum isolation, run Claude inside a container:
docker run -it -v $(pwd):/workspace -w /workspace \
node:20 npx @anthropic-ai/claude-code --dangerously-skip-permissionsWhen to sandbox:
- Running on untrusted codebases
- CI/CD pipelines where Claude generates or modifies code
- Evaluations and benchmarks where you need reproducibility
Inside a container, --dangerously-skip-permissions is safe because the blast radius is limited to the container filesystem.
Best Practices
- Start restrictive, loosen as needed. Begin with default mode and explicitly whitelist commands you trust.
- Per-project settings. Keep
.claude/settings.jsonin your repo so every team member gets the same permissions. - Settings precedence. Highest → lowest: managed policy (
managed-settings.json, deployed by IT) > command-line arguments > local project (.claude/settings.local.json, gitignored) > shared project (.claude/settings.json) > user (~/.claude/settings.json). Managed settings can lock downbypassPermissionsandautomodes org-wide. Note thatdefaultMode: "auto"is honored only from user or managed settings, not checked-in project settings. - Audit with hooks. Use Hooks to log or block tool calls. A
PreToolUsehook can enforce policies that CLAUDE.md cannot guarantee. - Use
denyfor hard blocks.denyrules overrideallow, so"deny": ["Bash(rm -rf *)"]is unconditionally enforced regardless of other settings.
How do agent permission models work?
Permission systems are a core design pattern in autonomous agents. Claude Code's layered approach — modes, allowlists, and hooks — maps directly to the principle of least privilege used in production agent architectures.
Related Reading
- Hooks — Enforce permissions programmatically with lifecycle hooks
- CLAUDE.md & Memory — Set project-level constraints and conventions
- Git & Parallel Sessions — Use worktrees for file isolation
- Workflows — See permissions in action across development workflows
Continue with practice
You have finished the core ideas of Permissions & Security.
If you want to turn the idea into something reusable, continue practicing on AgentWay.