Complete Guide to hooks.json Configuration Options in Everything Claude Code
The hooks.json file in the affaan-m/everything-claude-code repository defines six lifecycle hook events—PreToolUse, PreCompact, SessionStart, PostToolUse, Stop, and SessionEnd—that accept matcher patterns, command definitions, and optional async and timeout parameters to customize Claude Code's behavior.
The hooks.json file serves as the central configuration hub for the Everything Claude Code (ECC) plugin, defining when and how custom scripts intercept Claude's tool execution flow. This JSON configuration follows the Claude Code settings schema and enables developers to inject validation, formatting, and governance checks at precise moments during a coding session. Understanding the available configuration options allows you to enforce code quality, block unsafe operations, and automate post-processing tasks.
Hook Lifecycle Events
The configuration file organizes hooks into six distinct lifecycle events that fire at specific points during a Claude session. Each event array contains objects that define which tools trigger the hook and what commands execute in response.
PreToolUse
Defined in lines 4-99 of hooks/hooks.json, the PreToolUse event runs before any tool (Bash, Write, Edit, etc.) executes. This event is ideal for validation, security checks, or blocking unsafe flags before they reach the system.
PreCompact
Located at lines 100-110, PreCompact fires before the automatic context-compaction step occurs. Use this to persist state, dump diagnostics, or capture session metrics before Claude condenses the conversation history.
SessionStart
Found at lines 111-124, SessionStart executes once when a new Claude session begins. This hook can load prior session data, detect package managers, or initialize environment-specific configurations.
PostToolUse
Defined in lines 125-158, PostToolUse runs after a tool finishes execution. This is the appropriate place for formatting, type-checking, quality-gate checks, or logging tool outcomes.
Stop
Located at lines 162-236, the Stop event triggers when the assistant stops responding after each turn. This hook enforces final linting, captures governance events, or computes session costs before the next user input.
SessionEnd
Found at lines 237-274, SessionEnd represents the final hook before the process exits. Typically, this writes a clean termination marker for downstream analytics or cleanup operations.
Core Configuration Schema
Each hook entry within the event arrays follows a strict schema with required and optional keys that control execution behavior.
matcher
The matcher key defines a tool-pattern string (e.g., Bash, Write, Edit|Write) that determines which tool invocations trigger the hook. The pattern supports the pipe character (|) to match multiple tools and the asterisk (*) as a wildcard to match all tools.
hooks
The hooks key contains an array of action objects. Currently, ECC exclusively uses "type": "command" objects, which specify a shell command—usually a Node.js or Bash script—to execute when the matcher criteria are met.
description
The optional description field provides human-readable text explaining the hook's purpose. This documentation aids maintenance and debugging when reviewing complex configuration files.
async
When set to true, the async flag runs the hook non-blocking, allowing the assistant to continue processing without waiting for the command to complete. This is essential for long-running analysis tasks that should not interrupt the coding flow.
timeout
The timeout parameter specifies the maximum seconds a hook may run before the system forcibly terminates it. This prevents runaway scripts from hanging the Claude session indefinitely.
Execution Order and Matching Logic
The runtime evaluates hook execution through a precise matching sequence. First, the system identifies the current lifecycle event (PreToolUse, PostToolUse, etc.). Then, it evaluates each entry's matcher against the tool name being invoked. The first entry that matches runs its associated command, and multiple entries can match sequentially, executing in the order they appear in the JSON array.
Built-in Hook Implementations
The default hooks.json includes several production-ready hooks that demonstrate practical configurations:
PreToolUsewith matcherBash: Executesnpx block-no-verify@1.1.2to prevent--no-verifyflags that would bypass git hooksPreToolUsewith matcherWrite: Runsscripts/hooks/doc-file-warning.jsto warn when non-standard documentation files are editedPostToolUsewith matcherEdit: Callsscripts/hooks/post-edit-format.jsto auto-format JavaScript/TypeScript files after editsPostToolUsewith matcherEdit: Invokesscripts/hooks/post-edit-typecheck.jsto run TypeScript type-checking on.ts/.tsxfilesStopwith matcher*: Executesscripts/hooks/check-console-log.jsto scan modified files for strayconsole.logstatementsSessionEndwith matcher*: Runsscripts/hooks/session-end-marker.jsto emit a lifecycle marker for downstream analytics
Custom Configuration Examples
Blocking Destructive Bash Commands
Add this PreToolUse hook to prevent accidental recursive deletions:
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/run-with-flags.js\" \"pre:protect-rm\" \"scripts/hooks/protect-rm.js\" \"standard,strict\""
}
],
"description": "Blocks accidental recursive deletes"
}
Place this object inside the PreToolUse array. The protect-rm.js script inspects process.argv and exits with an error if the pattern /rm\s+-rf/ is detected.
Enforcing Linting on File Writes
Configure this PostToolUse hook to run a linter after any write operation:
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "npm run lint --silent"
}
],
"description": "Enforces linting on every file write"
}
Add this entry to the PostToolUse event array. The npm run lint script must be defined in the repository's package.json.
Non-Blocking Async Analysis
Use the async flag for long-running build analysis without blocking the assistant:
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/post-bash-build-complete.js\"",
"async": true,
"timeout": 30
}
],
"description": "Runs static-analysis after a build without blocking the assistant"
}
This mirrors the built-in example on lines 140-146 of hooks/hooks.json, allowing 30 seconds for static analysis to complete while Claude continues responding.
Custom Session Initialization
Override default startup behavior with a custom SessionStart hook:
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/custom-session-start.js\""
}
],
"description": "Loads a user-specific context file when a session begins"
}
Insert this object in the SessionStart array to execute custom logic when a new Claude session initializes.
Key Files and Implementation Details
Several supporting scripts work alongside hooks.json to provide the full hook infrastructure:
hooks/hooks.json: The master configuration file defining all events, matchers, and commandsscripts/hooks/run-with-flags.js: A wrapper utility that normalizes flag handling for every hook commandscripts/hooks/post-edit-format.js: Concrete formatter implementation used afterEditoperationsscripts/hooks/post-edit-typecheck.js: TypeScript type-checking script executed after file modificationsscripts/hooks/quality-gate.js: Comprehensive quality gate suite triggered after file changesscripts/hooks/check-console-log.js: Scanner that detects strayconsole.logstatements when theStopevent firesscripts/hooks/session-end-marker.js: Utility that emits terminal markers during session termination
These files collectively define the complete lifecycle of hook execution inside the ECC environment.
Summary
- The
hooks.jsonconfiguration supports six lifecycle events:PreToolUse,PreCompact,SessionStart,PostToolUse,Stop, andSessionEnd - Each hook requires a
matcherpattern (supporting|and*wildcards) and ahooksarray containing command definitions - Optional
asyncandtimeoutparameters control execution blocking and script duration limits - Hooks execute sequentially in the order they appear in the JSON array, with the first matching pattern triggering the associated command
- Built-in implementations demonstrate security validation, auto-formatting, type-checking, and session analytics
Frequently Asked Questions
What is the difference between PreToolUse and PostToolUse hooks?
PreToolUse hooks execute before Claude invokes a tool, making them ideal for validation, security checks, or blocking dangerous commands before they run. PostToolUse hooks execute after the tool completes, which is the appropriate place for formatting, linting, or logging the results of an operation. According to the source code in hooks/hooks.json, PreToolUse is defined at lines 4-99 while PostToolUse occupies lines 125-158.
Can I use wildcards in the matcher pattern?
Yes. The matcher field supports the asterisk (*) as a wildcard to match all tool types, and the pipe character (|) to match multiple specific tools (e.g., "Edit|Write"). This pattern matching is evaluated sequentially, with the first matching entry in the array executing its command.
How do I prevent a hook from blocking the assistant's response?
Set the async property to true within the hook definition. This runs the command non-blocking, allowing Claude to continue processing while the script executes in the background. Always pair async hooks with a timeout value to prevent runaway processes from consuming system resources indefinitely.
Where are the actual hook scripts located in the repository?
The hook scripts reside in the scripts/hooks/ directory, while the master configuration lives at hooks/hooks.json. Key scripts include run-with-flags.js (a wrapper for normalized execution), post-edit-format.js (for code formatting), and check-console-log.js (for governance scanning). The configuration references these using the ${CLAUDE_PLUGIN_ROOT} environment variable to ensure portable path resolution.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →