# Claude Code Hooks

> Source: https://aiwiki.ai/wiki/claude_code_hooks
> Updated: 2026-09-27
> Fact-checked: 2026-09-27
> Categories: AI Code Generation, Anthropic, Developer Tools
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/) - attribute to "AI Wiki (aiwiki.ai)"
> Cite as: AI Wiki. "Claude Code Hooks." aiwiki.ai, 27 Sept 2026. https://aiwiki.ai/wiki/claude_code_hooks
> From AI Wiki (https://aiwiki.ai), the free encyclopedia of artificial intelligence. Reuse freely with attribution.

Claude Code hooks connect [Claude Code](https://aiwiki.ai/wiki/claude_code) session events to automation, such as checking proposed tool calls or formatting edits. Command hooks provide programmatic checks; prompt and agent hooks use model judgment.[1]

This reference follows Anthropic's documentation checked on September 27, 2026. Consult the installed version and release history when maintaining older configurations.[6]

## Choose the event

The following is a selection of common events, not an exhaustive catalog.[1]

| Need | Event | Timing |
|---|---|---|
| Inspect a proposed tool call | `PreToolUse` | Before execution |
| Process a successful tool result | `PostToolUse` | After execution |
| Handle an approval request | `PermissionRequest` | When permission is requested |
| Check a response ending | `Stop` | When Claude finishes responding |

`Stop` marks a response ending, not necessarily task completion. Check `stop_hook_active` to avoid loops. Plain `claude -p` lacks the usual interactive approval prompt; consult `PermissionRequest` restrictions before relying on that event.[1]

## Configuration locations

Settings locations: user `~/.claude/settings.json`, shared project `.claude/settings.json`, private project `.claude/settings.local.json`. Managed policy takes precedence.[3]

The example below is an entry to merge into a settings file, not a replacement for that file. Keep unrelated configuration intact. Start in a disposable project before adopting a hook across a team.

## Decisions and safety boundaries

Command hooks receive event JSON on stdin. `PreToolUse` exit `2` blocks the call; exit `0` without a decision leaves normal permission checks in place. `PermissionRequest` requires its JSON decision object and ignores exit `2`. A post-tool hook cannot undo execution. Ordinary exit `1` is generally a non-blocking error.[2]

A synchronous `PreToolUse` command, HTTP, or MCP-tool hook that times out supplies no decision, and normal permission processing continues. An Agent SDK callback timeout instead blocks. Command hooks run with full user privileges.[2]

For the configuration below, `Edit|Write` matches either tool. Exec form uses `command` plus `args` without a shell. `${CLAUDE_PROJECT_DIR}` identifies the starting project root. The five-second timeout is a waiting limit, not a fail-closed guarantee.[2]

A Bash sandbox does not automatically isolate hook commands.[2][5]

## Example: check sensitive filenames

This original example rejects direct `Edit` and `Write` requests with a `.git` path segment, basename `.env`, or basename beginning `.env.`. It deliberately rejects `.env.example` too. The policy is a demonstration, not a recommended list of every sensitive file.

Save the script as `.claude/hooks/check-edit.cjs` in a test project with a current Node.js installation:

```javascript
const fs = require("node:fs");

function block(message) {
  process.stderr.write(message + "\n");
  process.exit(2);
}

let event;
try {
  event = JSON.parse(fs.readFileSync(0, "utf8"));
} catch {
  block("Cannot validate this edit: invalid event JSON.");
}

if (!event || event.hook_event_name !== "PreToolUse") {
  block("Cannot validate this edit: unexpected event.");
}

if (!["Edit", "Write"].includes(event.tool_name)) {
  process.exit(0);
}

const filePath = event.tool_input?.file_path;
if (typeof filePath !== "string" || filePath.length === 0) {
  block("Cannot validate this edit: missing file_path.");
}

const segments = filePath.replaceAll("\\", "/").split("/");
const basename = segments.at(-1);
if (
  segments.includes(".git") ||
  basename === ".env" ||
  basename.startsWith(".env.")
) {
  block("This filename is excluded from direct Edit and Write calls.");
}

process.exit(0);
```

Use this settings entry:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "node",
            "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/check-edit.cjs"],
            "timeout": 5
          }
        ]
      }
    ]
  }
}
```

The script only reads stdin and evaluates strings. It never opens the requested file, writes to that path, or launches another program. That makes fictional paths sufficient for its standalone tests. Its own behavior can be checked without installing a hook.

For a POSIX shell, run:

```bash
printf '%s\n' '{"hook_event_name":"PreToolUse","tool_name":"Write","tool_input":{"file_path":"/demo/.env"}}' | node .claude/hooks/check-edit.cjs
echo $?
```

The expected result is a diagnostic and exit `2`. Replacing `/demo/.env` with `/demo/src/main.js` produces no output and exit `0`.

| Fixture | Expected script result |
|---|---|
| `/demo/.env.production` | Reject |
| `/demo/.git/config` | Reject |
| `C:\demo\.env` | Reject after separator normalization |
| `/demo/.environment` | Pass this check |
| Missing `file_path` for `Write` | Reject |
| Malformed JSON | Reject |
| A `Read` tool call targeting `.env` | Pass this check because the script only checks edits |

These expectations describe the script, not complete Claude Code authorization. A standalone pass does not prove that the application loaded the configuration, that no other hook interfered, or that the eventual tool call succeeded. Verify those separately in a disposable session.

The code also has intentional limits. It does not resolve symbolic links or normalize filesystem case. An alias such as `/demo/secret-link` is not recognized as a sensitive target, and `.ENV` differs from `.env` in its string comparison. It does not inspect shell commands or external processes. Extending this small filename filter into a general access-control system would require a different design.

## Operational review

Review repository configuration before trusting its executable behavior. Anthropic's security guidance warns about [prompt injection](https://aiwiki.ai/wiki/prompt_injection), recommends reviewing proposed commands and critical changes, and notes that non-interactive `-p` operation disables the interactive trust verification. A repository's checked-in automation deserves the same scrutiny as its build scripts.[4]

For a deployment review, record the installed version, configuration source, intended event, expected rejection behavior, and a small set of allowed and rejected fixtures. Add a deliberately broken-script test: observe the permission outcome when the interpreter is unavailable or the program fails. This distinguishes "the validator rejected the request" from "the validator never completed."

Retain test output without collecting real credentials or full private prompts. A diagnostic that states which rule failed is often enough for this example; recording the target file contents would serve no purpose because the script never evaluates them.

For related configuration topics, see [Claude Code Permissions and Sandboxing](https://aiwiki.ai/wiki/claude_code_permissions_and_sandboxing) and [Claude Code CLI Flags](https://aiwiki.ai/wiki/claude_code_cli_flags).

## References

1. Anthropic. ["Automate actions with hooks."](https://code.claude.com/docs/en/hooks-guide) Claude Code documentation. Accessed September 27, 2026.
2. Anthropic. ["Hooks reference."](https://code.claude.com/docs/en/hooks) Claude Code documentation. Accessed September 27, 2026.
3. Anthropic. ["Settings files and precedence."](https://code.claude.com/docs/en/settings) Claude Code documentation. Accessed September 27, 2026.
4. Anthropic. ["Security."](https://code.claude.com/docs/en/security) Claude Code documentation. Accessed September 27, 2026.
5. Anthropic. ["Configure the sandboxed Bash tool."](https://code.claude.com/docs/en/sandboxing) Claude Code documentation. Accessed September 27, 2026.
6. Anthropic. ["Claude Code changelog."](https://code.claude.com/docs/en/changelog) Official release history. Accessed September 27, 2026.

