Applied Intelligence
Module 2: The Agent Mental Model

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:

PriorityLocationScope
1 (Highest)System managed-settings.jsonEnterprise-wide enforcement
2.claude/settings.jsonProject (shared with team)
3~/.claude/settings.jsonUser (all projects)
4 (Lowest).claude/settings.local.jsonLocal 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 plan

Configuring 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:

  • Write matches all write operations
  • Write(*.py) matches Python file writes
  • Bash(npm *) matches npm commands
  • Read(**/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.

EventWhen it firesCan block
PreToolUseBefore tool executionYes (exit code 2)
PostToolUseAfter tool completionNo
PermissionRequestWhen permission is requestedNo
StopWhen agent stops respondingNo
SubagentStopWhen subagent completesNo
SessionEndWhen session terminatesNo

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 0

Starting 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:

  • /permissions shows current settings
  • /hooks provides an interactive interface for managing hook configuration

When behavior seems incorrect, these commands reveal the active configuration affecting the session.

On this page