/hook
Configure, create, or troubleshoot Claude Code hooks (PreToolUse, PostToolUse, UserPromptSubmit), debug hook failures, or set up any automation within Claude Code. Examples include "I want to run tests before every file edit", "My hook isn't firing", "1 out of 2 hooks ran", or
$ npx -y skills add bendrucker/claude --skill hook --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/hook
Context preview
The summary Claude sees to decide when to auto-load this skill.
Configure, create, or troubleshoot Claude Code hooks (PreToolUse, PostToolUse, UserPromptSubmit), debug hook failures, or set up any automation within Claude Code. Examples include "I want to run tests before every file edit", "My hook isn't firing", "1 out of 2 hooks ran", or
SKILL.md
hook.SKILL.mdname: claude-code:hook
description: Configure, create, or troubleshoot Claude Code hooks (PreToolUse, PostToolUse, UserPromptSubmit), debug hook failures, or set up any automation within Claude Code. Examples include "I want to run tests before every file edit", "My hook isn't firing", "1 out of 2 hooks ran", or "How do I create a hook that formats JSON output with jq?"
allowed-tools:
- Read
- Write
- Edit
- Glob
- Grep
- Bash
- WebFetch(domain:docs.anthropic.com)
Claude Code Hooks
Reference for creating and configuring Claude Code hooks. When uncertain about syntax or features, use the `Agent` tool with `subagent_type='claude-code-guide'` to consult official docs.
Hook Types
| Type | Trigger | Use Cases | |------|---------|-----------| | PreToolUse | Before tool execution | Validate inputs, block operations, modify parameters | | PostToolUse | After tool completes | Check results, run linters, provide feedback | | UserPromptSubmit | When user sends message | Pre-process input, add context | | PermissionRequest | Permission dialog appears | Return a decision, notify a remote approver | | Stop | Agent finishes a turn | Cleanup, save state | | StopFailure | Agent stops on failure | Report the failure | | SubagentStart / SubagentStop | Subagent spawns / completes | Process results | | SessionStart / SessionEnd | Session begins / ends | Inject context, export state | | PreCompact / PostCompact | Around context compaction | Save important state | | Notification | System notification | Log events | | TeammateIdle | Teammate about to go idle | Hand off work |
Configuration Files
- `~/.claude/settings.json` - User-level (global)
- `.claude/settings.json` - Project-level
- `.claude/settings.local.json` - Local (not committed)
- Plugin hooks: `plugins/<name>/hooks/hooks.json`
Hook Structure
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bun ./hooks/biome"
}
]
}
]
}
}Matcher Patterns
- Simple: `"Write"`, `"Edit"`
- Multiple: `"Edit|Write|MultiEdit"`
- With args: `"Bash(npm:*)"`, `"Bash(osascript:*)|Bash(open:*)"`
- MCP tools: `"mcp__linear__create_issue"`
- Plugin MCP tools: `"mcp__plugin_<plugin>_<namespace>__<tool>"`
- Claude AI MCP tools: `"mcp__claude_ai_<DisplayName>__<tool>"`
- All three patterns: `"mcp__linear__create_issue|mcp__plugin_linear_linear__create_issue|mcp__claude_ai_Linear__save_issue"`
Hook Input
Commands receive JSON on stdin:
{
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.ts",
"content": "..."
},
"cwd": "/project/root",
"session_id": "...",
"transcript_path": "..."
}Parse in TypeScript:
import type { PreToolUseHookInput } from "@anthropic-ai/claude-agent-sdk";
const input = JSON.parse(await Bun.stdin.text()) as PreToolUseHookInput;Hook Output
**PreToolUse** - Control execution:
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Use gh cli instead"}}{"hookSpecificOutput": {"hookEventName": "PreToolUse", "updatedInput": {"state": "Todo"}}}**PostToolUse** - Provide feedback:
{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "Lint errors found..."}}Exit with no output to allow without modification.
Async
`"async": true` on a command hook backgrounds it so the turn does not wait. Nothing above reaches the model: no `permissionDecision`, no `updatedInput`, no `additionalContext`, and exit code 2 does not block. Verified on 2.1.220 that stderr and a nonzero exit are both dropped. `"asyncRewake": true` backgrounds the hook but wakes the model on exit code 2, delivering stderr (or stdout when stderr is empty) as a system reminder. Neither field applies to `prompt` or `agent` hooks.
Use `async` only for a hook that is a pure side effect: a notifier, a status bridge, a terminal bell, a state export. Keep it off when the hook returns any of the output above, mutates state a later step reads, or gates a tool call.
Two events behave differently from the rest, measured on 2.1.220:
- `Stop` kills the backgrounded process almost immediately. Anything past a few milliseconds never finishes. A `Stop` notifier must stay synchronous.
- `SessionEnd` outlives the CLI. A backgrounded hook there runs to completion after the process exits, making it safe to background.
`SubagentStop`, `SessionStart`, `UserPromptSubmit`, and `PostToolUse` all run to completion when backgrounded.
Hooks on the same event already run concurrently with each other, so `async` only shortens the turn when the side-effect hook is the slowest one on its event. It is still worth setting on a hook that qualifies, because the payoff moves as sibling hooks change.
Script Storage
Store complex hooks in `.claude/hooks/` or a project `hooks/` directory, referenced with:
"command": "bun $CLAUDE_PROJECT_DIR/.claude/hooks/my-hook.ts"
Examples
See these repositories for hook implementations:
- Input modification: [plugins/linear/hooks/](plugins/linear/hooks/)
- Permission decisions: [plugins/github/scripts/](plugins/github/scripts/)
- PostToolUse feedback: [.claude/hooks/biome/](.claude/hooks/biome/)
Debugging
For troubleshooting hook failures, see [debugging](references/debugging.md).
Read more
name: claude-code:hook description: Configure, create, or troubleshoot Claude Code hooks (PreToolUse, PostToolUse, UserPromptSubmit), debug hook failures, or set up any automation within Claude Code. Examples include "I want to run tests before every file edit", "My hook isn't firing", "1 out of 2 hooks ran", or "How do I create a hook that formats JSON output with jq?" allowed-tools: - Read - Write - Edit - Glob - Grep - Bash - WebFetch(domain:docs.anthropic.com)
Claude Code Hooks
Reference for creating and configuring Claude Code hooks. When uncertain about syntax or features, use the `Agent` tool with `subagent_type='claude-code-guide'` to consult official docs.
Hook Types
| Type | Trigger | Use Cases | |------|---------|-----------| | PreToolUse | Before tool execution | Validate inputs, block operations, modify parameters | | PostToolUse | After tool completes | Check results, run linters, provide feedback | | UserPromptSubmit | When user sends message | Pre-process input, add context | | PermissionRequest | Permission dialog appears | Return a decision, notify a remote approver | | Stop | Agent finishes a turn | Cleanup, save state | | StopFailure | Agent stops on failure | Report the failure | | SubagentStart / SubagentStop | Subagent spawns / completes | Process results | | SessionStart / SessionEnd | Session begins / ends | Inject context, export state | | PreCompact / PostCompact | Around context compaction | Save important state | | Notification | System notification | Log events | | TeammateIdle | Teammate about to go idle | Hand off work |
Configuration Files
- `~/.claude/settings.json` - User-level (global)
- `.claude/settings.json` - Project-level
- `.claude/settings.local.json` - Local (not committed)
- Plugin hooks: `plugins/<name>/hooks/hooks.json`
Hook Structure
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bun ./hooks/biome"
}
]
}
]
}
}Matcher Patterns
- Simple: `"Write"`, `"Edit"`
- Multiple: `"Edit|Write|MultiEdit"`
- With args: `"Bash(npm:*)"`, `"Bash(osascript:*)|Bash(open:*)"`
- MCP tools: `"mcp__linear__create_issue"`
- Plugin MCP tools: `"mcp__plugin_<plugin>_<namespace>__<tool>"`
- Claude AI MCP tools: `"mcp__claude_ai_<DisplayName>__<tool>"`
- All three patterns: `"mcp__linear__create_issue|mcp__plugin_linear_linear__create_issue|mcp__claude_ai_Linear__save_issue"`
Hook Input
Commands receive JSON on stdin:
{
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.ts",
"content": "..."
},
"cwd": "/project/root",
"session_id": "...",
"transcript_path": "..."
}Parse in TypeScript:
import type { PreToolUseHookInput } from "@anthropic-ai/claude-agent-sdk";
const input = JSON.parse(await Bun.stdin.text()) as PreToolUseHookInput;Hook Output
**PreToolUse** - Control execution:
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Use gh cli instead"}}{"hookSpecificOutput": {"hookEventName": "PreToolUse", "updatedInput": {"state": "Todo"}}}**PostToolUse** - Provide feedback:
{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "Lint errors found..."}}Exit with no output to allow without modification.
Async
`"async": true` on a command hook backgrounds it so the turn does not wait. Nothing above reaches the model: no `permissionDecision`, no `updatedInput`, no `additionalContext`, and exit code 2 does not block. Verified on 2.1.220 that stderr and a nonzero exit are both dropped. `"asyncRewake": true` backgrounds the hook but wakes the model on exit code 2, delivering stderr (or stdout when stderr is empty) as a system reminder. Neither field applies to `prompt` or `agent` hooks.
Use `async` only for a hook that is a pure side effect: a notifier, a status bridge, a terminal bell, a state export. Keep it off when the hook returns any of the output above, mutates state a later step reads, or gates a tool call.
Two events behave differently from the rest, measured on 2.1.220:
- `Stop` kills the backgrounded process almost immediately. Anything past a few milliseconds never finishes. A `Stop` notifier must stay synchronous.
- `SessionEnd` outlives the CLI. A backgrounded hook there runs to completion after the process exits, making it safe to background.
`SubagentStop`, `SessionStart`, `UserPromptSubmit`, and `PostToolUse` all run to completion when backgrounded.
Hooks on the same event already run concurrently with each other, so `async` only shortens the turn when the side-effect hook is the slowest one on its event. It is still worth setting on a hook that qualifies, because the payoff moves as sibling hooks change.
Script Storage
Store complex hooks in `.claude/hooks/` or a project `hooks/` directory, referenced with:
"command": "bun $CLAUDE_PROJECT_DIR/.claude/hooks/my-hook.ts"
Examples
See these repositories for hook implementations:
- Input modification: [plugins/linear/hooks/](plugins/linear/hooks/)
- Permission decisions: [plugins/github/scripts/](plugins/github/scripts/)
- PostToolUse feedback: [.claude/hooks/biome/](.claude/hooks/biome/)
Debugging
For troubleshooting hook failures, see [debugging](references/debugging.md).
My personal plugin marketplace for Claude Code, Anthropic's AI coding assistant.
Repo: bendrucker/claude
Other skills on bendrucker-claude.
- /agent-ideas
Harvest agent-tooling ideas from prominent developers.
Open skill - /cleye
Type-safe CLI argument parsing with cleye, the standard parser for this repo's Bun scripts. Use when writing or editing any script that takes arguments (flags, positional parameters, subcommands, --help) instead of reading existing scripts for the pattern.
Open skill - /coverage
Measure Bun test coverage and close gaps on a specific file. Use when adding or editing tests, when asked about coverage, or when the PostToolUse coverage hook reports uncovered lines.
Open skill - /activity
Report real device usage from ActivityWatch. Covers per-app time, window titles, and active vs idle spans. Use when asked "what apps did I use", "how long was I in X", "what did I work on today", "how much was I active vs idle", or to mine usage patterns for automation.
Open skill - /history
Report shell history from atuin's local capture. Covers what commands ran, when, where, and how they exited. Use when asked "what commands did I run", "what was I working on in the terminal", "have I ever run X", "how do I usually invoke X", or about recent shell activity,
Open skill - /bun
Bun runtime patterns. Use when running bun commands, working with package.json/bun.lock, writing TypeScript scripts under Bun, or developing Claude Code plugins.
Open skill

