# How to Configure and Use Claude Code Hooks: Matcher Syntax, Hook Types, and Runtime Controls

> Learn to configure and use Claude Code hooks. Explore matcher syntax, hook types, and runtime controls to extend Claude's capabilities. Follow our guide for effective integration.

- Repository: [Affaan Mustafa/everything-claude-code](https://github.com/affaan-m/everything-claude-code)
- Tags: how-to-guide
- Published: 2026-03-20

---

**Claude Code hooks are extensibility scripts declared in [`hooks/hooks.json`](https://github.com/affaan-m/everything-claude-code/blob/main/hooks/hooks.json) that execute at specific lifecycle phases, filtered by matcher syntax like `Bash|Write` or `*`, and controlled through profile flags parsed by [`scripts/hooks/run-with-flags.js`](https://github.com/affaan-m/everything-claude-code/blob/main/scripts/hooks/run-with-flags.js).**

Claude Code hooks enable developers to intercept tool executions and session events through a declarative JSON configuration system. This guide covers the architecture implemented in the `everything-claude-code` repository, detailing how to configure hook phases, leverage matcher syntax for precise targeting, and apply runtime controls for secure, conditional execution.

## Hook Lifecycle Phases

The [`hooks/hooks.json`](https://github.com/affaan-m/everything-claude-code/blob/main/hooks/hooks.json) registry defines six distinct phases where **Claude Code hooks** can intercept execution. The engine iterates over hook arrays in the order declared under each top-level key:

- **PreToolUse**: Executes immediately before any tool (Bash, Write, Edit, MultiEdit) runs. Use this phase to validate arguments or enforce security policies.
- **PreCompact**: Fires before context-compaction operations. Ideal for persisting state or dumping diagnostics.
- **SessionStart**: Triggers at the beginning of a new Claude Code session. Commonly used to detect package managers or restore previous context.
- **PostToolUse**: Runs after a tool finishes execution. Supports asynchronous operations for non-blocking quality gates or governance capture.
- **Stop**: Executes after every assistant response, before the next user input. Use for scanning prohibited patterns or storing session metadata.
- **SessionEnd**: Runs when the session terminates (e.g., upon `/stop` command). Handles cleanup, final markers, or analytics flushing.

Each phase contains an array of hook objects that the runtime engine processes sequentially.

## Matcher Syntax for Targeting Tools

The **`matcher`** field determines which tool invocations trigger a hook. The syntax supports three patterns:

- **Exact tool names**: `Bash`, `Write`, `Edit`, or `MultiEdit`
- **Pipe-separated alternatives**: `Bash|Write|Edit` matches any of the listed tools
- **Wildcard**: `*` matches every tool invocation

The engine performs simple string comparison against the current tool name. No regular expressions are required.

```json
{
  "matcher": "Edit|Write",
  "hooks": [
    {
      "type": "command",
      "command": "node scripts/hooks/suggest-compact.js"
    }
  ],
  "description": "Suggest manual compaction at logical intervals"
}

```

This configuration triggers only when the Edit or Write tools are invoked.

## Declaring Hooks in hooks.json

A valid hook object requires three properties:

1. **`matcher`**: String defining which tools activate the hook (see Matcher Syntax above)
2. **`hooks`**: Array of action objects, each containing `type` (typically `"command"`) and the shell `command` to execute
3. **`description`**: Human-readable explanation displayed in the UI

Optional fields control execution behavior:

- **`async`** (boolean): When `true`, the hook runs in the background without blocking the main flow. Essential for expensive analysis that must not delay user responses.
- **`timeout`** (seconds): Maximum execution duration before the engine forcibly terminates the hook process.

```json
{
  "matcher": "*",
  "hooks": [
    {
      "type": "command",
      "command": "node scripts/hooks/telemetry.js",
      "async": true,
      "timeout": 5
    }
  ],
  "description": "Async telemetry for every tool use"
}

```

## Runtime Controls and Security

The [`scripts/hooks/run-with-flags.js`](https://github.com/affaan-m/everything-claude-code/blob/main/scripts/hooks/run-with-flags.js) dispatcher implements granular controls for **Claude Code hooks** through profile flags and security sandboxing.

### Profile-Based Flagging

Hooks can be conditionally enabled via the `isHookEnabled(hookId, { profiles })` function (lines 49-52 in [`run-with-flags.js`](https://github.com/affaan-m/everything-claude-code/blob/main/run-with-flags.js)). Pass a CSV list of profiles as the third argument to the script:

```bash
node scripts/hooks/run-with-flags.js "hook-id" "script.js" "standard,strict"

```

Active profiles are determined by environment variables:

- **`ECC_ENABLE_INSAITS=1`**: Enables the InsAIts security monitor (PreToolUse hook, lines 78-86)
- **`ECC_GOVERNANCE_CAPTURE=1`**: Activates governance capture hooks (PreToolUse and PostToolUse, lines 86-98 and 190-198)
- **`ECC_HOOK_PROFILE=standard,strict`**: Defines which comma-separated profiles are active; defaults to `standard`

If a hook's required profiles do not intersect with active profiles, the engine skips execution and passes stdin through unchanged.

### Execution Modes and Timeouts

- **Synchronous** (default): Claude Code waits for hook completion before proceeding. Required for actions affecting the next step, such as argument validation.
- **Asynchronous** (`"async": true`): The hook spawns in parallel; the assistant returns results immediately. Use for build notifications or heavy analysis.
- **Timeout enforcement**: The `timeout` field (seconds) caps execution time. The engine kills processes exceeding this limit and logs warnings (see spawning logic at lines 101-108).

### Security Safeguards

The runtime implements multiple protective measures:

- **Path-traversal protection**: [`run-with-flags.js`](https://github.com/affaan-m/everything-claude-code/blob/main/run-with-flags.js) verifies that resolved script paths remain within the plugin root directory (lines 58-63).
- **Require-export optimization**: Scripts exposing `module.exports.run` are loaded directly via `require()` instead of child process spawning, reducing attack surface (lines 71-99).
- **Environment sanitization**: Child processes inherit `process.env`, but only explicit flags and the plugin root path influence hook enablement logic.

## Practical Configuration Examples

### Blocking Dangerous Git Commands

Use a PreToolUse hook with the `Bash` matcher to prevent `--no-verify` flags that bypass git hooks:

```json
{
  "matcher": "Bash",
  "hooks": [
    {
      "type": "command",
      "command": "npx block-no-verify@1.1.2"
    }
  ],
  "description": "Block git hook-bypass flag to protect pre-commit, commit-msg, and pre-push hooks"
}

```

### Auto-Starting Development Servers

Launch long-running dev servers