8.2 Permissions
Course: Claude Code - Power User Section: Configuration Video Length: 3-5 minutes Presenter: Daniel Treasure
Opening Hook
Permissions are how you tell Claude Code what it can and cannot do. Three rules—Allow, Ask, Deny—and a powerful pattern syntax that lets you be as specific as you need.
Key Talking Points
1. The Three Permission Rules
- Allow: Action runs automatically without approval
- Ask: Claude Code prompts you for permission before running
- Deny: Action is blocked completely
- Apply at user, project, and enterprise levels
- Rules cascade like settings (more specific wins)
What to say: "These three rules give you complete control. You can let Claude handle routine stuff, ask for dangerous operations, and block everything you never want."
What to show on screen: Show a clean table or diagram with examples: - Allow: npm run test, read .env, edit src/ - Ask: git commit, npm install, bash commands - Deny: rm -rf, sudo, docker run
2. Permission Patterns (Gitignore-Style Syntax)
- Uses gitignore syntax for matching
- Supports wildcards, globs, and recursion
- Format:
ACTION(target) - Examples:
bash(npm run *)= any npm run commandread(./.env)= specific fileedit(/src/**/*.ts)= all .ts files in src recursivelyWebFetch(domain:example.com)= domain-specific web fetches
What to say: "The pattern syntax is the same idea as .gitignore. If you've written gitignore patterns, you already know how to write permission rules."
What to show on screen: Show a side-by-side comparison of gitignore and permission patterns, then walk through 4-5 real examples
3. Scope Levels
- User level: Broad defaults, applied everywhere
- Project level: Team rules, shared in repo
- Enterprise level: Org policies, can't be overridden
- Each can refine or strengthen the one below
- Permission inheritance is additive (more rules = more restrictive)
What to say: "Start permissive at the user level, then get stricter for sensitive projects. Your org might lock down everything, and that's okay—it's a feature."
What to show on screen: Demo cascading permissions: - User allows npm run * - Project adds "ask for npm install" - Effective result: npm run allowed, npm install requires ask
4. Real-World Permission Strategies
- Development machine: Allow most things, ask for git commands
- CI/CD pipeline: Allow only specific whitelisted actions, deny everything else
- Team project: Ask for file modifications outside src/, deny production deployments
- Open-source contribution: Deny file writes, allow reads and specific test runs
What to say: "Different contexts need different rules. Your local machine is different from CI, which is different from a pull request environment."
What to show on screen: Show 2-3 settings.json examples with realistic permission blocks, explain the reasoning for each
5. Permission Syntax Deep-Dive
bash(command)= bash/shell commandsread(path)= read filesedit(path)= modify/create filesWebFetch(domain:...)= HTTP requestsbash(git *)= git commands (can be granular)bash(docker *)= docker operationsbash(npm *)= npm/package manager- Wildcards:
*(any),**(recursive),?(single char)
What to say: "Most of the time you'll use bash, read, edit, and maybe WebFetch. The patterns let you be as broad or specific as needed."
What to show on screen: Build up a complex permission block line-by-line, explaining each rule
Demo Plan
- Show current permissions (1 min)
- Open a project's
.claude/settings.json - Highlight the
permissionssection - Explain the current allow/ask/deny rules
-
Walk through what each rule does
-
Demonstrate pattern matching (1 min 30 sec)
- Test a pattern against real files:
bash(npm run *)should matchnpm run test,npm run build, etc. - Show a deny pattern that blocks dangerous commands:
bash(rm -rf *) -
Explain why you'd use each
-
Scenario: Adding a new rule (1 min 30 sec)
- Team needs to allow TypeScript builds but ask before installing dependencies
- Show how to add:
"ask": ["bash(npm install *)", "bash(npm add *)"] -
Explain the impact: "Now when Claude tries to npm install, I approve first"
-
Permission denial in action (optional, 30 sec)
- Try to run a denied command, show the block message
-
Explain why the rule exists
-
Preview next video (30 sec)
- "Model configuration is about speed vs power. Let's pick the right tool for the job."
Code Examples & Commands
Basic user-level permissions:
{
"permissions": {
"allow": [
"bash(npm run *)",
"read(./)",
"edit(src/**/*)"
],
"ask": [
"bash(git commit *)",
"bash(npm install *)",
"bash(npm add *)"
],
"deny": [
"bash(rm -rf *)",
"bash(sudo *)",
"bash(git push *)"
]
}
}
Strict project-level permissions (e.g., for CI/CD):
{
"permissions": {
"allow": [
"bash(npm run test)",
"bash(npm run build)",
"read(./)"
],
"ask": [],
"deny": [
"bash(*)"
]
}
}
Team-friendly permissions:
{
"permissions": {
"allow": [
"bash(npm run *)",
"bash(npm test)",
"edit(src/**/*.ts)",
"read(./)"
],
"ask": [
"edit(.*config.*)",
"bash(git *)",
"bash(npm install *)",
"bash(npm publish *)"
],
"deny": [
"bash(docker *)",
"bash(sudo *)",
"bash(rm -rf *)"
]
}
}
Web fetch restrictions by domain:
{
"permissions": {
"allow": [
"WebFetch(domain:github.com)",
"WebFetch(domain:*.npmjs.org)",
"WebFetch(domain:nodejs.org)"
],
"deny": [
"WebFetch(domain:*)"
]
}
}
File-specific edit permissions:
{
"permissions": {
"allow": [
"edit(src/**/*.ts)",
"edit(tests/**/*.spec.ts)",
"read(./)"
],
"deny": [
"edit(package.json)",
"edit(.env*)",
"edit(*.config.js)"
]
}
}
Gotchas & Tips
- Order matters (sort of): In practice, Deny wins over Allow. If something is in deny, it's blocked.
- Patterns are greedy:
bash(*)blocks ALL bash commands. Be specific unless you mean it. - WebFetch domain syntax: Use
domain:example.comfor exact domain ordomain:*.example.comfor subdomains. - Inherited and additive: Project permissions don't replace user permissions—they add on top. More rules = more restrictions.
- Test your patterns: Try a pattern first in a safe environment before rolling it out.
- Communicate rules to the team: Put a comment in
.claude/settings.jsonexplaining why each rule exists. - Ask is not always safe: An "ask" rule still lets Claude run the command after you approve. For truly dangerous ops, use Deny.
Lead-out
Permissions are your safety net. Once you understand these three rules, you can be confident that Claude Code operates within the bounds you've set. Next, we'll talk model configuration—choosing the right Claude for the job.
Reference URLs
- Permission patterns documentation: https://claude.ai/docs/claude-code/permissions
- Gitignore pattern syntax (for reference): https://git-scm.com/docs/gitignore
- Common permission templates: [team wiki]
Prep Reading
- Understand gitignore syntax (basic wildcards and glob patterns)
- Think about what operations you'd allow vs deny in your workflow
- Review the permission rule types (allow/ask/deny)
- Consider different use cases: personal dev machine, team project, CI/CD
Notes for Daniel: Permissions are often the "ah-ha!" moment for users—they realize they have fine-grained control. Lean on the gitignore analogy hard. For demo, use your actual project's settings.json so the examples feel real and relevant. If you deny a command live, make sure you explain the security reason, not just "because." Keep the energy positive: "You're now in control."