Permissions

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 default for 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=1 and currently support only Opus 4.7 or Opus 4.8.
  • dontAsk — Auto-deny anything not in your permissions.allow list. 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:

bash
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 CI

For 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:

json
{
  "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:

json
{
  "permissions": {
    "ask": ["Bash(npm install *)", "Edit"]
  }
}

Directory & File Restrictions

Restrict write access to specific directories using permissions.additionalDirectories or CLAUDE.md instructions:

markdown
## 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 command

For 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):

json
{
  "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:

bash
docker run -it -v $(pwd):/workspace -w /workspace \
  node:20 npx @anthropic-ai/claude-code --dangerously-skip-permissions

When 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.json in 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 down bypassPermissions and auto modes org-wide. Note that defaultMode: "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 PreToolUse hook can enforce policies that CLAUDE.md cannot guarantee.
  • Use deny for hard blocks. deny rules override allow, 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.

Learn about Agent Architecture

Related Reading

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.