Configuring Claude Code
Settings files hierarchy; permission modes; hooks for automation
CLAUDE.md shapes what the agent does, while settings files shape how it does it. A CLAUDE.md might say "always run tests before committing," but a settings file determines whether the agent asks permission before executing those tests.
The settings hierarchy
Claude Code reads settings from multiple locations, with higher-priority sources overriding lower ones:
| Priority | Location | Scope |
|---|---|---|
| 1 (Highest) | System managed-settings.json | Enterprise-wide enforcement |
| 2 | .claude/settings.json | Project (shared with team) |
| 3 | ~/.claude/settings.json | User (all projects) |
| 4 (Lowest) | .claude/settings.local.json | Local overrides (not committed) |
System locations:
- macOS:
/Library/Application Support/ClaudeCode/managed-settings.json - Linux/WSL:
/etc/claude-code/managed-settings.json - Windows:
C:\ProgramData\ClaudeCode\managed-settings.json
Permission modes
Claude Code operates in one of four permission modes that control agent autonomy:
- Default mode Prompts for permission on first use of each tool. After approving a specific operation, subsequent identical operations proceed without asking.
- AcceptEdits mode Auto-accepts file modifications. Still asks permission for potentially destructive operations like shell commands.
- Plan mode Restricts to read-only operations. The agent can analyze files and develop plans but cannot modify files or execute commands.
- BypassPermissions mode Auto-accepts all operations. Dangerous can cause data loss and execute arbitrary commands. Reserve for isolated environments.
Press Shift+Tab to cycle modes, or use the CLI flag:
claude --permission-mode planConfiguring permissions
Settings files specify granular permission rules through allow and deny patterns:
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test:*)",
"Read(~/.zshrc)"
],
"deny": [
"Bash(curl:*)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
}
}Deny rules take precedence over allow rules when both match. This enables broad allows with specific carve-outs: "allow all Bash commands except those involving credentials."
Pattern syntax:
Writematches all write operationsWrite(*.py)matches Python file writesBash(npm *)matches npm commandsRead(**/config/*)matches config files in any directory
Hooks for automation
Hooks are user-defined shell commands that execute at lifecycle events. Unlike CLAUDE.md instructions, hooks provide deterministic control they always execute regardless of whether the agent "decides" to run them.
| Event | When it fires | Can block |
|---|---|---|
| PreToolUse | Before tool execution | Yes (exit code 2) |
| PostToolUse | After tool completion | No |
| PermissionRequest | When permission is requested | No |
| Stop | When agent stops responding | No |
| SubagentStop | When subagent completes | No |
| SessionEnd | When session terminates | No |
PostToolUse example
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$file\""
}
]
}
]
}
}This runs Prettier after any file edit or write, ensuring consistent formatting without relying on the agent.
PreToolUse blocking example
#!/bin/bash
# ~/.claude/hooks/block-sensitive-files.sh
file_path=$(jq -r '.tool_input.file_path' < /dev/stdin)
if [[ "$file_path" =~ \.(env|pem|key)$ ]]; then
echo "Error: Cannot modify sensitive file: $file_path" >&2
exit 2
fi
exit 0Starting with version 2.0.10, PreToolUse hooks can also modify tool inputs. By outputting JSON with an updatedInput field, hooks can transform dangerous commands into safer equivalents.
Practical configuration patterns
Team-shared project settings
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(pnpm *)",
"Bash(git status)",
"Bash(git diff *)"
],
"deny": [
"Bash(git push *)",
"Read(.env*)"
]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Write(*.ts)|Write(*.tsx)|Edit",
"hooks": [{"type": "command", "command": "npx prettier --write \"$file\""}]
}
]
}
}User-level defaults
{
"permissionMode": "acceptEdits",
"disableBypassPermissionsMode": "disable"
}Debugging configuration
Two commands help verify current configuration:
/permissionsshows current settings/hooksprovides an interactive interface for managing hook configuration
When behavior seems incorrect, these commands reveal the active configuration affecting the session.