Claude Code Settings

Table of Contents

1. Introduction

Claude Code uses a hierarchical settings system with multiple configuration files. Settings are merged with the following precedence (highest to lowest):

  1. Enterprise managed policies
  2. Command-line arguments
  3. Local project settings (.claude/settings.local.json)
  4. Shared project settings (.claude/settings.json)
  5. User settings (~/.claude/settings.json)

This means local settings override shared project settings, which override user settings.

1.1. Settings Philosophy

  • Project settings: Version-controlled, shared with team
  • Local settings: Git-ignored, personal overrides
  • User settings: Personal defaults for all projects

1.2. Common Use Cases

  • Restrict dangerous tools (project settings)
  • Set project-specific environment variables (project settings)
  • Configure personal notification hooks (local settings)
  • Set default model preference (local/user settings)

2. Project Settings (Shared)

These settings are version-controlled and shared with the team. Configure project-wide policies, permissions, and environment variables here.

2.1. Core Configuration

{
  "permissions": {
    "allow": [
      "WebSearch",
      "Bash(mkdir:*)",
      "Bash(mv:*)",
      "Bash(git add:*)",
      "Bash(git commit:*)",
      "Bash(git push:*)"
    ],
    "deny": []
  },
  "env": {
    "PROJECT_ROOT": "/Users/kyeongsoo/Projects/mandoo180.github.io"
  },
  "enableAllProjectMcpServers": true,
  "enabledMcpjsonServers": [
    "emacs",
    "filesystem"
  ]
}

2.2. Permissions Explained

2.2.1. Allow List

The allow list explicitly permits specific tools or tool patterns:

  • WebSearch - Allow web searches for up-to-date information
  • Bash(mkdir:*) - Safe directory creation
  • Bash(mv:*) - File moving operations
  • Bash(git add:*) - Staging changes
  • Bash(git commit:*) - Creating commits
  • Bash(git push:*) - Pushing to remote

Pattern matching: Use * as wildcard. Bash(git:*) would match all git commands.

2.2.2. Deny List

The deny list blocks specific operations. Empty by default, but you might add:

"deny": [
  "Bash(rm -rf:*)",
  "Bash(dd:*)",
  "Bash(mkfs:*)"
]

This prevents destructive operations that could cause data loss.

2.2.3. Tool Names

Common tools you can allow/deny:

  • Read - Reading files
  • Write - Writing files
  • Edit - Editing files
  • Bash(command:*) - Bash commands (use wildcards)
  • WebSearch - Web searching
  • WebFetch - Fetching URLs
  • Glob - File pattern matching
  • Grep - Content searching

2.3. Environment Variables

Set project-specific environment variables available to all Claude Code sessions:

"env": {
  "PROJECT_ROOT": "/path/to/project",
  "NODE_ENV": "development",
  "PYTHONPATH": "./src:./lib",
  "CUSTOM_VAR": "value"
}

Use cases:

  • Project root path for scripts
  • Environment type (dev/staging/prod)
  • Custom paths (Python, Node modules)
  • Feature flags

2.4. MCP Server Configuration

2.4.1. Enable All Project Servers

"enableAllProjectMcpServers": true

When true, all servers defined in .mcp.json are automatically enabled.

2.4.2. Selective Server Enablement

"enableAllProjectMcpServers": false,
"enabledMcpjsonServers": [
  "emacs",
  "filesystem"
]

Explicitly list which MCP servers to enable from .mcp.json.

3. Local Settings (Personal)

These settings are git-ignored and personal to each developer. Use for preferences, experimental features, and local tools.

3.1. Example Configuration

{
  "model": "sonnet",
  "alwaysThinkingEnabled": false
}

3.2. Common Local Settings

3.2.1. Model Selection

{
  "model": "sonnet"  // or "opus", "haiku"
}

Override the default model for this project.

3.2.2. Thinking Mode

{
  "alwaysThinkingEnabled": false
}

Control whether Claude shows internal reasoning by default.

3.2.3. Notification Hooks

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "terminal-notifier -title 'Claude Code' -message 'Awaiting input'"
          }
        ]
      }
    ]
  }
}

Run system notifications when Claude needs input (macOS example).

4. Advanced Configuration

4.1. Hooks System

Hooks execute commands before/after tool usage, enabling powerful workflow automation.

4.1.1. Hook Structure

{
  "hooks": {
    "ToolName": [
      {
        "matcher": "pattern",
        "hooks": [
          {
            "type": "command",
            "position": "before",  // or "after"
            "command": "command to run",
            "blocking": true
          }
        ]
      }
    ]
  }
}

4.1.2. Example: Git Status Before Commit

{
  "hooks": {
    "Bash": [
      {
        "matcher": "git commit",
        "hooks": [
          {
            "type": "command",
            "position": "before",
            "command": "git status",
            "blocking": true
          }
        ]
      }
    ]
  }
}

Shows git status before any commit command.

4.1.3. Example: Notification on Completion

{
  "hooks": {
    "Bash": [
      {
        "matcher": "npm test",
        "hooks": [
          {
            "type": "command",
            "position": "after",
            "command": "terminal-notifier -title 'Tests' -message 'Test run complete'"
          }
        ]
      }
    ]
  }
}

Desktop notification when tests finish.

4.1.4. Hook Parameters

  • matcher - Pattern to match (empty string matches all)
  • type - Currently only "command" is supported
  • position - "before" or "after" tool execution
  • command - Shell command to execute
  • blocking - If true, wait for command to complete

4.2. Sandbox Settings

Control sandboxing behavior for added security.

{
  "sandbox": {
    "enabled": true,
    "allowedPaths": [
      "/Users/kyeongsoo/Projects"
    ]
  }
}

Warning: Modifying sandbox settings can affect security. Only change if you understand the implications.

4.3. Custom Tool Permissions

Fine-grained control over tool behavior.

{
  "permissions": {
    "allow": [
      "Read",
      "Write(/path/to/allowed/*)",
      "Bash(ls:*)",
      "Bash(grep:*)"
    ],
    "deny": [
      "Write(/etc/*)",
      "Bash(sudo:*)"
    ]
  }
}

Use path patterns for Write and command patterns for Bash.

5. Settings Hierarchy Example

Understanding how settings merge:

5.1. User Settings (~/.claude/settings.json)

{
  "model": "sonnet",
  "alwaysThinkingEnabled": false,
  "permissions": {
    "allow": ["Read", "Write"]
  }
}

5.2. Project Settings (.claude/settings.json)

{
  "permissions": {
    "allow": ["Read", "Write", "Bash(git:*)"]
  },
  "env": {
    "PROJECT_ROOT": "/path/to/project"
  }
}

5.3. Local Settings (.claude/settings.local.json)

{
  "model": "opus",
  "hooks": {
    "Notification": [...]
  }
}

5.4. Effective Settings

After merging (local > project > user):

{
  "model": "opus",  // from local (overrides user)
  "alwaysThinkingEnabled": false,  // from user
  "permissions": {
    "allow": ["Read", "Write", "Bash(git:*)"]  // from project
  },
  "env": {
    "PROJECT_ROOT": "/path/to/project"  // from project
  },
  "hooks": {
    "Notification": [...]  // from local
  }
}

6. Best Practices

6.1. Do's

  • Version control .claude/settings.json for team consistency
  • Use local settings for personal preferences
  • Document why specific tools are allowed/denied
  • Test hooks before committing them to project settings
  • Use environment variables for project-specific paths

6.2. Don'ts

  • Don't commit .claude/settings.local.json (it's personal)
  • Don't hardcode absolute paths in project settings when possible
  • Don't allow overly broad permissions (Bash(*:*) is dangerous)
  • Don't store secrets or API keys in settings (use environment variables)
  • Don't override security policies without understanding implications

6.3. Security Considerations

  1. Principle of least privilege: Only allow tools that are needed
  2. Deny dangerous operations: rm -rf, dd, mkfs, sudo
  3. Restrict filesystem access: Use path patterns in Write permissions
  4. Review hooks carefully: Hooks execute arbitrary commands
  5. Version control project settings: Team reviews for security

7. Troubleshooting

7.1. Settings Not Taking Effect

  • Restart Claude Code after changing settings
  • Check JSON syntax with jq . .claude/settings.json
  • Verify file is in correct location
  • Check settings precedence (local > project > user)

7.2. Permission Denied Errors

  • Check permissions.allow includes required tool
  • Verify no deny rule is blocking it
  • Check pattern matching (* wildcard usage)
  • Try more specific pattern if broad pattern doesn't work

7.3. Hooks Not Running

  • Verify JSON syntax is correct
  • Check matcher pattern matches the tool usage
  • Test command manually in terminal first
  • Check Claude Code logs for error messages
  • Ensure blocking is set if you need sequential execution

8. Related Configuration

9. Resources