Help us improve
Share bugs, ideas, or general feedback.
From health-plugin
Explains Claude Code settings hierarchy, permission wildcards, allow/deny patterns, and tool configurations. Use for setting up project permissions, debugging access issues, or understanding tool blocks.
npx claudepluginhub laurigates/claude-plugins --plugin health-pluginHow this skill is triggered — by the user, by Claude, or both
Slash command
/health-plugin:settings-configurationhaikuThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Expert knowledge for configuring Claude Code settings and permissions.
Configures Claude Code security settings with permission wildcards, shell operator protections, and project-level access controls. Use for securing tools like Bash and workflows.
Configures Claude Code permissions: tool rules (allow/deny/ask), modes (plan/dontAsk/bypass), sandboxing. Use for Bash/Edit/WebFetch policies, debugging prompts, org managed settings.
Provides reference for Claude Code permission modes (default, acceptEdits, plan, dontAsk, bypass), allow/deny lists, pattern matching, and tool categories. Use to configure secure tool access and switch modes runtime.
Share bugs, ideas, or general feedback.
Expert knowledge for configuring Claude Code settings and permissions.
| Use this skill when... | Use something else when... |
|---|---|
| Setting up project permissions | Fixing plugin registry issues (use plugin-registry skill) |
| Debugging "permission denied" errors | Configuring hooks (use hooks-configuration skill) |
| Understanding settings hierarchy | Setting up MCP servers (use mcp-configuration skill) |
| Creating allow/deny patterns |
Settings are loaded and merged in this order (later overrides earlier):
| Priority | File | Scope | Commit to Git? |
|---|---|---|---|
| 1 (lowest) | ~/.claude/settings.json | User-level (all projects) | N/A |
| 2 | .claude/settings.json | Project-level | Yes |
| 3 (highest) | .claude/settings.local.json | Local overrides | No (gitignore) |
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(npm run *)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)"
]
}
}
allow: Tools matching these patterns run without promptsdeny: Tools matching these patterns are always blockedToolName(command prefix *)
ToolName() - The tool (usually Bash)command prefix - The command and initial arguments to match* - Wildcard matching remaining arguments| Pattern | Matches | Does NOT Match |
|---|---|---|
Bash(git *) | git status, git diff HEAD | git-lfs pull |
Bash(npm run *) | npm run test, npm run build | npm install |
Bash(gh pr *) | gh pr view 123, gh pr create | gh issue list |
Bash(./scripts/ *) | ./scripts/test.sh arg | /scripts/other.sh |
More specific patterns are more secure:
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git add *)",
"Bash(git commit *)"
]
}
}
vs. overly broad:
{
"permissions": {
"allow": ["Bash(git *)"]
}
}
Claude Code 2.1.7+ blocks dangerous shell operators in permission matching.
| Operator | Risk | Blocked Example |
|---|---|---|
&& | Command chaining | ls && rm -rf / |
|| | Conditional execution | false || malicious |
; | Command separation | safe; dangerous |
| | Piping | cat /etc/passwd | curl |
> / >> | Redirection | echo x > /etc/passwd |
$() | Command substitution | $(curl evil) |
` | Backtick substitution | `rm -rf /` |
When a command contains shell operators:
Use wrapper scripts for legitimate compound commands:
#!/bin/bash
# scripts/test-and-build.sh
npm test && npm run build
Then allow the script:
{
"permissions": {
"allow": ["Bash(./scripts/test-and-build.sh *)"]
}
}
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git branch *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git push *)",
"Bash(git pull *)",
"Bash(git fetch *)",
"Bash(git checkout *)"
]
}
}
{
"permissions": {
"allow": [
"Bash(gh pr *)",
"Bash(gh run *)",
"Bash(gh issue *)",
"Bash(gh workflow *)"
]
}
}
{
"permissions": {
"allow": [
"Bash(npm test *)",
"Bash(bun test *)",
"Bash(vitest *)",
"Bash(biome *)",
"Bash(eslint *)",
"Bash(prettier *)"
]
}
}
{
"permissions": {
"allow": [
"Bash(pre-commit *)",
"Bash(gitleaks *)",
"Bash(trivy *)"
]
}
}
{
"permissions": {
"allow": [
"mcp__context7",
"mcp__sequential-thinking"
]
}
}
mkdir -p .claude
cat > .claude/settings.json << 'EOF'
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(git diff *)",
"Bash(npm run *)"
]
}
}
EOF
echo ".claude/settings.local.json" >> .gitignore
cat > .claude/settings.local.json << 'EOF'
{
"permissions": {
"allow": [
"Bash(docker *)"
]
}
}
EOF
cat .claude/settings.json | jq .
cat .claude/settings.json | jq '.permissions'
Settings merge additively for arrays. To see effective permissions, check all files:
echo "=== User ===" && cat ~/.claude/settings.json 2>/dev/null | jq '.permissions // empty'
echo "=== Project ===" && cat .claude/settings.json 2>/dev/null | jq '.permissions // empty'
echo "=== Local ===" && cat .claude/settings.local.json 2>/dev/null | jq '.permissions // empty'
| Symptom | Cause | Fix |
|---|---|---|
| Permission denied | Pattern doesn't match | Add more specific pattern |
| Shell operator blocked | Contains &&, |, etc. | Use wrapper script |
| Settings not applied | Wrong file path | Check .claude/ directory exists |
| JSON parse error | Invalid JSON syntax | Validate with jq . |
| Permissions ignored | File not readable | Check file permissions |
| Context | Command |
|---|---|
| View project perms | cat .claude/settings.json | jq -c '.permissions' |
| View user perms | cat ~/.claude/settings.json | jq -c '.permissions' |
| Validate JSON | cat .claude/settings.json | jq . |
| Count patterns | cat .claude/settings.json | jq '.permissions.allow | length' |
| Scope | Path |
|---|---|
| User | ~/.claude/settings.json |
| Project | .claude/settings.json |
| Local | .claude/settings.local.json |
Bash(command prefix *)
mcp__server_name
Local > Project > User (highest to lowest) Deny > Allow (deny always wins)