Run a shell command on lifecycle events with hooks
mcp, agents & hooks
// what it does
Hooks run your own shell commands at fixed lifecycle events — PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, and more — configured under the hooks key in settings.json. Each event holds matchers (a tool-name regex like Write|Edit) and command entries. A PostToolUse hook that runs a formatter after every Write or Edit is the classic example; hooks receive event JSON on stdin.
// shell
$ { "hooks": { "PostToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": "npm run lint --silent" } ] } ] } }$ /hooks// gotcha
Exit code 2 blocks the action and feeds stderr back to Claude; any other non-zero code is a non-blocking error. Unlike CLAUDE.md, hooks execute regardless of what Claude decides, so use one for anything that must always happen. Reference scripts with ${CLAUDE_PROJECT_DIR} so paths resolve from the project root.