Published: May 20, 2026
Category: Guides
> Quick Answer: Claude Code hooks are user-defined scripts that run automatically at specific points in Claude's workflow. Set up an afterWrite hook to auto-format every file Claude touches, an afterTask hook to run your test suite, or a beforeCommand hook to validate shell commands. Hooks run locally, use your existing tools, and require zero API calls.
Hooks are shell scripts that Claude Code triggers at specific moments: before or after it writes a file, runs a command, or completes a task. You define the trigger and the command. Claude handles the rest.
The practical value is automation. Without hooks, your workflow is: Claude writes code, you notice it didn't run Prettier, you manually format, you realize you forgot to run tests, you run them yourself. With hooks, all of that happens automatically the moment Claude finishes writing.
Hooks run synchronously in your local environment. Claude waits for them to finish before continuing, which means they're reliable for enforcement tasks like linting or validation.
Claude Code has three extension mechanisms:
Skills (SKILL.md) shape what Claude does. A code review skill tells Claude what to look for and how to structure its feedback. Skills are instructions. Browse skills at Agensi.
MCP servers connect Claude to external data and tools. An MCP server might let Claude query your database or search a skill marketplace.
Hooks automate actions around Claude's workflow. They don't change Claude's behavior. They add automated steps before or after Claude does something.
All three work together. A skill tells Claude how to review code, an MCP server provides context from your issue tracker, and a hook auto-runs the linter after Claude writes its changes.
Add hooks to your Claude Code settings file. Project-level hooks go in .claude/settings.json. User-level hooks go in ~/.claude/settings.json.
Each hook needs an event (when to trigger), an optional file pattern, and a command:
{
"hooks": {
"afterWrite": [
{
"pattern": "*.ts",
"command": "npx prettier --write $FILE"
},
{
"pattern": "*.py",
"command": "black $FILE"
}
],
"afterTask": [
{
"command": "npm test"
}
]
}
}
This formats every TypeScript file with Prettier, formats every Python file with Black, and runs your test suite after Claude completes any task.
beforeCommand fires before Claude executes a shell command. Use it to validate commands, check permissions, or log activity.
afterCommand fires after a shell command finishes. Use it to check exit codes, parse output, or trigger follow-up actions.
beforeWrite fires before Claude writes or modifies a file. Use it to back up the original or validate the file path.
afterWrite fires after Claude writes a file. This is the most common hook. Use it for formatting, linting, or type checking.
afterTask fires after Claude finishes a complete task. Use it for running test suites, building the project, or sending notifications that the task is done.
Auto-formatting on every write. Claude doesn't always match your project's formatting rules. An afterWrite hook running your formatter keeps everything consistent without you thinking about it.
Running tests after every task. An afterTask hook that runs npm test or pytest catches regressions immediately. Claude sees the failures and can fix them in the same session.
Linting TypeScript and JavaScript. An afterWrite hook running ESLint catches project-specific rule violations that Claude's code generation might miss.
Git staging changed files. An afterWrite hook that runs git add $FILE keeps your staging area in sync with Claude's changes.
Desktop notifications. An afterTask hook that triggers a system notification when Claude finishes a long task. Useful when you're doing other work while Claude codes.
{
"hooks": {
"afterWrite": [
{
"pattern": "*.{ts,tsx}",
"command": "npx prettier --write $FILE && npx eslint --fix $FILE"
}
],
"afterTask": [
{
"command": "npm test && osascript -e 'display notification \"Task complete\" with title \"Claude Code\"'"
}
]
}
}
Yes. Hooks run as regular shell commands in your project's working directory. They have access to all your environment variables, project files, and local tools. Claude Code passes the relevant file path as $FILE for file-related hooks.
This means hooks can read your .env files, use project-specific tool configurations like .eslintrc or pyproject.toml, and interact with any CLI tool installed on your system.
Hooks run synchronously, so a slow hook blocks Claude. A linter that takes 200ms is fine. A full build step that takes 30 seconds will make every file write feel sluggish. Keep hooks fast.
Hooks run locally on your machine. They can't modify Claude's thinking or responses, only act on the files and commands Claude produces.
If a hook fails (non-zero exit code), Claude Code reports the failure but continues its task. Hooks flag issues, they don't block Claude from completing work.
They complement each other well. A SKILL.md skill can include recommended hook configurations in its documentation. When you install a code review skill, the README might suggest an afterWrite hook that runs a security linter. When you install a testing skill, it might recommend an afterTask hook for the specific test framework it generates tests for.
For skills that pair well with hooks, browse the Testing and QA and Code Review categories on Agensi.