Configuring hooks-config.json vs hooks-config.local.json in Claude Code: Team Defaults vs Personal Overrides

Claude Code uses hooks-config.json for team-wide defaults committed to the repository, while hooks-config.local.json provides git-ignored personal overrides that take precedence when loaded by the hook runtime.

The shanraisshan/claude-code-best-practice repository implements a sophisticated hook system that balances team consistency with individual developer preferences. Understanding how to configure hooks-config.json versus hooks-config.local.json allows teams to share standardized auditory feedback and automation while letting developers silence specific hooks locally without polluting the shared codebase.

Understanding the Two Configuration Files

Team-Wide Defaults with hooks-config.json

The .claude/hooks/config/hooks-config.json file serves as the shared baseline for all repository collaborators. Because this file is committed to version control, it ensures every team member experiences consistent hook behavior—such as audio notifications on SessionStart or TaskCompleted events. The JSON structure contains Boolean flags for every hook event, including disableLogging, disablePreToolUseHook, disablePermissionRequestHook, and disableSessionStartHook.

Personal Overrides with hooks-config.local.json

The .claude/hooks/config/hooks-config.local.json file is git-ignored and resides only on individual workstations. Developers create this file to override specific flags from the team config without modifying the shared repository. According to the implementation in hooks.py, this local file loads after the team configuration, meaning any keys defined here take precedence while unspecified flags inherit the team defaults.

Configuration Precedence and Merge Logic

The hook runtime implemented in .claude/hooks/scripts/hooks.py follows a specific loading order to resolve configuration conflicts. First, the system loads hooks-config.json to establish the baseline. Then, if present, it loads hooks-config.local.json and merges the two dictionaries, with local values overwriting team values for any matching keys.

This merge strategy enables partial overrides. For example, if the team config enables SessionStart sounds but a developer wants to silence only that specific hook while keeping all other team defaults, they only need to specify "disableSessionStartHook": true in their local file.

Practical Configuration Examples

Team-wide configuration (committed to .claude/hooks/config/hooks-config.json):

{
  "disableLogging": false,
  "disablePreToolUseHook": false,
  "disablePermissionRequestHook": false,
  "disablePostToolUseHook": false,
  "disablePostToolUseFailureHook": false,
  "disableUserPromptSubmitHook": false,
  "disableNotificationHook": false,
  "disableStopHook": false,
  "disableSubagentStartHook": false,
  "disableSubagentStopHook": false,
  "disablePreCompactHook": false,
  "disableSessionStartHook": false,
  "disableSessionEndHook": false,
  "disableSetupHook": false,
  "disableTeammateIdleHook": false,
  "disableTaskCompletedHook": false,
  "disableConfigChangeHook": false,
  "disableWorktreeCreateHook": false,
  "disableWorktreeRemoveHook": false,
  "disableInstructionsLoadedHook": false
}

Personal override (created locally at .claude/hooks/config/hooks-config.local.json):

{
  "disableLogging": true,
  "disablePostToolUseHook": true,
  "disableSessionStartHook": true
}

Global hook disable (in .claude/settings.local.json for complete silence):

{
  "disableAllHooks": true
}

Key Files and Implementation Details

File Purpose Location
hooks-config.json Team-wide default configuration .claude/hooks/config/hooks-config.json
hooks-config.local.json Personal overrides (git-ignored) .claude/hooks/config/hooks-config.local.json
hooks.py Runtime implementation that merges configs and executes hooks .claude/hooks/scripts/hooks.py
settings.local.json Global disable switch for all hooks .claude/settings.local.json
CLAUDE.md Architecture documentation for the hooks system CLAUDE.md (Hooks System section)
HOOKS-README.md Detailed usage guide for hook configuration .claude/hooks/HOOKS-README.md

Summary

  • hooks-config.json provides version-controlled team defaults for Claude Code hook behavior, ensuring consistent automation across all collaborators.
  • hooks-config.local.json offers git-ignored personal overrides that take precedence over team settings, allowing individual developers to customize their experience without modifying shared files.
  • The merge logic in hooks.py loads team configuration first, then applies local overrides, enabling partial customization while inheriting unspecified defaults.
  • For complete silence, use .claude/settings.local.json with "disableAllHooks": true to bypass both configuration files entirely.

Frequently Asked Questions

What happens if I only specify some keys in hooks-config.local.json?

The hook runtime merges your local file with the team defaults. Any keys you define in hooks-config.local.json override the team values, while all unspecified flags inherit the settings from hooks-config.json. This partial override mechanism lets you silence specific hooks like SessionStart while keeping all other team-defined behaviors intact.

Can I completely disable all hooks without editing the config files?

Yes. Create or edit .claude/settings.local.json in your workspace root and add "disableAllHooks": true. This global flag supersedes both hooks-config.json and hooks-config.local.json, effectively preventing the hook runtime in hooks.py from executing any hook actions. This is particularly useful for CI environments or performance-critical sessions.

Why is hooks-config.local.json git-ignored while hooks-config.json is committed?

The repository intentionally tracks hooks-config.json to ensure every team member shares the same baseline hook behavior, creating a consistent development environment. Conversely, hooks-config.local.json is listed in .gitignore because personal preferences—such as disabling audio notifications for specific events—vary by developer and should not be forced upon the entire team or clutter the repository history.

Where does the actual hook execution logic reside?

The runtime implementation lives in .claude/hooks/scripts/hooks.py. This Python script reads and merges the JSON configurations from both hooks-config.json and hooks-config.local.json, then executes the appropriate actions—such as playing audio files—for each enabled hook event. The script handles the precedence logic where local settings override team defaults during the configuration merge phase.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →