Skip to content

Permissions — Real-World Examples

Permissions control what Claude can do without asking. Good permission config means no interruptions during normal work, and strong safety guards for dangerous operations.


Think of permissions in two categories:

Allow list = things Claude does constantly Pre-approve these so work flows without interruptions.

Deny list = things that are irreversible or risky Block these even if Claude thinks they’re the right move.

Everything else falls through to your defaultMode — which determines whether to ask you, auto-approve, or block.


Real Example 1: Node.js / TypeScript Project

Section titled “Real Example 1: Node.js / TypeScript Project”

Situation: You want Claude to freely run npm commands, git operations, and file edits — but never force-push, delete files, or touch migrations.

{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npm test)",
"Bash(npm test -- *)",
"Bash(npm install)",
"Bash(npm install *)",
"Bash(npx *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git checkout *)",
"Bash(git branch *)",
"Bash(git pull)",
"Bash(git push origin *)",
"Bash(gh pr *)",
"Bash(gh issue *)",
"Read",
"Edit",
"Write",
"Glob",
"Grep"
],
"deny": [
"Bash(git push --force *)",
"Bash(git push -f *)",
"Bash(git reset --hard *)",
"Bash(git clean -f *)",
"Bash(rm -rf *)",
"Bash(sudo *)",
"Edit(.env)",
"Edit(.env.*)",
"Edit(prisma/migrations/**)",
"Edit(package-lock.json)"
]
},
"defaultMode": "default"
}

Result: Claude runs tests, edits code, commits, and opens PRs without a single prompt — but you see a confirmation dialog before force pushes or database migration changes.


Situation: Claude works on components and styles, but you don’t want it touching build config or CI/CD files.

{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npm test *)",
"Bash(npx *)",
"Bash(git *)",
"Bash(gh pr *)",
"Read",
"Edit(src/**)",
"Edit(public/**)",
"Edit(tests/**)",
"Write(src/**)",
"Write(tests/**)",
"Glob",
"Grep",
"WebFetch(domain:developer.mozilla.org)",
"WebFetch(domain:react.dev)",
"WebFetch(domain:tailwindcss.com)"
],
"deny": [
"Edit(.github/**)",
"Edit(*.config.js)",
"Edit(*.config.ts)",
"Edit(webpack.config.*)",
"Edit(vite.config.*)",
"Edit(.eslintrc*)",
"Bash(rm -rf *)",
"Bash(sudo *)"
]
}
}

Result: Claude freely works within src/ and tests/, but config files are locked — no accidental Webpack changes.


Situation: Claude runs in a GitHub Actions workflow. You want it to make code fixes and commit, but never interact with deployments or infrastructure.

{
"permissions": {
"allow": [
"Read",
"Edit",
"Write",
"Glob",
"Grep",
"Bash(npm run lint *)",
"Bash(npm run lint -- --fix)",
"Bash(npm test)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git push origin *)",
"Bash(git diff *)",
"Bash(git log *)"
],
"deny": [
"Bash(npm run deploy *)",
"Bash(kubectl *)",
"Bash(aws *)",
"Bash(gcloud *)",
"Bash(terraform *)",
"Bash(rm *)",
"Bash(sudo *)",
"WebFetch",
"WebSearch"
]
},
"defaultMode": "dontAsk"
}

"defaultMode": "dontAsk" means: if a tool isn’t pre-approved, Claude cannot use it (no prompting — CI has no human to answer). This makes CI usage predictable.


Situation: You want Claude in strict read-only mode for auditing — it should never modify anything.

{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Bash(git log *)",
"Bash(git diff *)",
"Bash(git blame *)",
"Bash(git show *)"
],
"deny": [
"Edit",
"Write",
"Bash(git commit *)",
"Bash(git push *)",
"Bash(git add *)",
"Bash(npm *)"
]
},
"defaultMode": "plan"
}

Or just use plan mode flag:

Terminal window
claude --permissions plan "Review the auth system for security issues"

Situation: Main session has normal permissions. The researcher agent is read-only. The deployer agent has deploy access but nothing else.

.claude/agents/researcher.md:

---
name: "researcher"
tools:
- Read
- Grep
- Glob
- WebSearch
- WebFetch
---
Read-only research agent. Never modifies files.

.claude/agents/deployer.md:

---
name: "deployer"
tools:
- Bash(npm run deploy:*)
- Bash(npm run smoke-test:*)
- Read
---
Deployment-only agent. Cannot edit source files.

Claude’s main session can edit code but can’t deploy. The deployer agent can deploy but can’t edit code. Separation of concerns enforced at the tool level.


Understanding how Bash patterns work:

Terminal window
"Bash" # allow ALL bash commands
"Bash(npm *)" # npm run, npm test, npm install, npm anything
"Bash(npm run *)" # npm run build, npm run dev, npm run test:watch
"Bash(npm run build)" # ONLY npm run build (exact match)
"Bash(git *)" # all git subcommands
"Bash(git push origin *)" # git push origin main, git push origin HEAD, etc.
"Bash(* --version)" # node --version, npm --version, etc.
"Bash(cat *)" # cat any file

Deny patterns work the same way:

Terminal window
"Bash(rm -rf *)" # blocks rm -rf anything
"Bash(git push --force *)"# blocks force push to any remote/branch
"Bash(sudo *)" # blocks all sudo commands

"Edit(src/**)" // any file under src/
"Edit(src/**/*.ts)" // TypeScript files under src/
"Edit(/etc/**)" // absolute path — use double slash: //etc/**
"Edit(~/.ssh/**)" // home dir paths
"Edit(.env)" // exact file match
"Edit(.env.*)" // .env.local, .env.production, etc.
"Read(node_modules/**)" // deny reading node_modules (performance)

{ "defaultMode": "default" }
ModeWhat happens for unlisted tools
defaultPrompt the user (approve/deny each time)
acceptEditsAuto-approve file edits; prompt for shell commands
planBlock all writes and shell; read-only browsing
autoClaude judges safety; approves safe things automatically
dontAskBlock everything not in allow list — no prompting
bypassPermissionsApprove everything — use only in sandboxed containers

Recommended for:

  • Daily dev work: default or acceptEdits
  • Exploring/researching: plan
  • CI/CD pipelines: dontAsk with a tight allow list
  • Quick local scripts: bypassPermissions (only if you trust the task fully)

You don’t have to restart to change modes:

Terminal window
Shift+Tab # cycles: default → acceptEdits → plan → auto → (back to default)

Example workflow:

  1. Start in plan mode — explore the codebase
  2. Shift+Tab to acceptEdits — make the changes
  3. Shift+Tab to plan — review what changed
  • Trick: “Start strict, loosen with evidence.”
  • Do: walk one scenario, then have learners write rules for their own repo.
  • They’ll trip on: copying someone else’s allowlist without understanding it.

Learning path:14-permissions.md · Index · ➡ 16-sandboxing-and-security.md

Written by Fenil Patel