2 min read
Managing Claude Code Permissions
Got tired of Claude asking permission for every command. Here's how I fixed it.
Got annoyed today. Every time Claude Code ran a command, it asked “Allow this?” Click yes. Next command. “Allow this?” Click yes again.
Decided to figure out how to stop this.
Where permissions live
Claude Code stores permissions in settings.json files:
~/.claude/settings.json # Global (all projects)
.claude/settings.json # Project (shared, git tracked)
.claude/settings.local.json # Project (personal, gitignored)
The structure is simple:
{
"permissions": {
"allow": ["Bash(git:*)", "Bash(npm:*)"],
"deny": ["Bash(rm -rf:*)"]
}
}
Finding what I actually use
Wanted to know which commands I’d been allowing across projects. Ran this:
find ~/Workspace -name "settings.local.json" -path "*/.claude/*" \
-exec cat {} \; | grep -oE '"Bash\([^)]+\)"' | \
sort | uniq -c | sort -rn
Output showed the winners:
4 xcodebuild
3 xargs
3 open
3 ls
3 find
2 tree
2 npm test
2 cat
2 grep
The fix
Added the frequent ones to my global config:
{
"permissions": {
"allow": [
"Bash(swift:*)",
"Bash(git:*)",
"Bash(ls:*)",
"Bash(find:*)",
"Bash(cat:*)",
"Bash(grep:*)",
"Bash(npm:*)",
"Bash(gh:*)",
"WebSearch"
],
"deny": [
"Bash(rm -rf:*)"
]
}
}
The :* suffix means “allow with any arguments.”
Gotchas
- When you click “Always allow” during a session, it saves to
settings.local.jsonin that project only - Global settings (
~/.claude/settings.json) apply everywhere denyrules overrideallow- good for blocking dangerous stuff likerm -rf
Now Claude just runs commands without asking. Much better.