Creating Custom Hooks
Relevant source files
The following files were used as context for generating this wiki page:- packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx
- packages/webapp/src/app/blog/claude-hooks-support/page.tsx
- packages/webapp/src/app/blog/kiro-hooks-automation/page.tsx
- packages/webapp/src/app/blog/format-specifications-guide/page.tsx
- packages/webapp/public/blog/extensibility-landscape.md
- CLAUDE.md
Hooks are event-driven automation scripts that run during AI coding sessions, allowing you to inject custom logic, enforce standards, and extend the capabilities of AI assistants like Claude Code and Kiro. They can automatically format code, log commands, protect sensitive files, or trigger complex workflows based on specific events.
PRPM simplifies the creation, management, and distribution of these hooks by treating them as packages. This allows for one-command installation, clean uninstalls, and sharing across teams and projects. This guide covers the architecture and best practices for creating custom hooks for various supported platforms.
Sources: packages/webapp/src/app/blog/claude-hooks-support/page.tsx:43-46, packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:43-45, packages/webapp/src/app/blog/kiro-hooks-automation/page.tsx:42-46
Hook Concepts
Hooks are fundamentally event-driven. They listen for specific events within an AI assistant's lifecycle and execute a script or command in response. The two primary hook systems supported are Claude Hooks and Kiro Hooks, each with a different event model.
- Claude Hooks: Trigger based on tool usage and session events within the Claude Code environment.
- Kiro Hooks: Trigger based on file system events like file creation, modification, or deletion.
- Droid Hooks: Trigger based on tool usage and can be executable scripts.
This modular approach allows for powerful, context-aware automation that integrates directly into the development workflow.
Sources: packages/webapp/src/app/blog/claude-hooks-support/page.tsx:50-53, packages/webapp/src/app/blog/kiro-hooks-automation/page.tsx:50-57, packages/webapp/public/blog/extensibility-landscape.md:329-332
Claude Hooks
Claude Hooks are automated scripts that run in response to events within Claude Code, such as tool usage or session state changes. They are configured in the .claude/settings.json file and are ideal for tasks like code formatting, command logging, and validation.
Sources: packages/webapp/src/app/blog/claude-hooks-support/page.tsx:50-53, 100-102
Architecture and Events
Claude Hooks are defined within the hooks object in settings.json. They are associated with specific events.
The following diagram illustrates the general execution flow of a Claude Hook.
This diagram shows how a Claude Code event triggers a configured hook, which then executes and returns a status code to influence the operation.
Sources: packages/webapp/src/app/blog/claude-hooks-support/page.tsx:100-102, packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:61-75
The primary supported events are:
| Event | Trigger Point | Common Use Case |
|---|---|---|
PreToolUse | Before Claude calls a tool (e.g., Write, Bash). | Block operations on sensitive files, validate input. |
PostToolUse | After a tool call completes successfully. | Format code after a file write, log command execution. |
UserPromptSubmit | When the user submits a message to the agent. | Pre-process or log user prompts. |
SessionStart | When a new Claude Code session begins. | Initialize a workflow or set up an environment. |
SessionEnd | When the Claude Code session is terminated. | Clean up resources or log session activity. |
Sources: packages/webapp/src/app/blog/claude-hooks-support/page.tsx:69-92, packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:91-102
Hook Configuration
A Claude Hook is a JSON object with several key fields. Hooks are defined in an array for each event type.
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "prettier --write \"${file}\"",
"timeout": 10000
}],
"__prpm_hook_id": "@prpm/prettier-on-save@1.0.0"
}]
}
}
Sources: packages/webapp/src/app/blog/claude-hooks-support/page.tsx:128-141, packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:143-152
The structure of a hook configuration is detailed below.
This diagram shows the JSON structure for a single Claude hook configuration.
Sources: packages/webapp/src/app/blog/format-specifications-guide/page.tsx:288-295, packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:143-152
Data Flow and Scripting
Hook scripts receive context from Claude via JSON on stdin. The script is responsible for parsing this input to perform its action.
A typical sequence for a prettier-on-save hook:
This sequence diagram illustrates a PostToolUse hook that formats a file after it's written by Claude.
Sources: packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:61-75, 230-242
Exit Codes
The exit code of your script determines the outcome of the operation:
exit 0: Success. The operation continues.exit 2: Block. The operation is safely prevented. This is used byPreToolUsehooks to stop an action, for example, on a sensitive file.- Any other code: Error. The hook has failed.
Sources: packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:324-328
Kiro Hooks
Kiro hooks are event-driven automations triggered by file system events. They are defined as individual JSON files in the .kiro/hooks/ directory and are well-suited for workflows that react to code changes, such as synchronizing tests or updating documentation.
Sources: packages/webapp/src/app/blog/kiro-hooks-automation/page.tsx:42-46, 73-75
Architecture and Events
Kiro's model is based on watching for file changes that match specified patterns.
| Event | Trigger |
|---|---|
fileCreated | A new file is created. |
fileModified | An existing file is changed. |
fileEdited | An existing file is changed (alias for fileModified). |
fileDeleted | A file is deleted. |
manual | Triggered on-demand by the user. |
Sources: packages/webapp/src/app/blog/kiro-hooks-automation/page.tsx:59-66, packages/webapp/src/app/blog/format-specifications-guide/page.tsx:614-617
Hook Configuration
Each Kiro hook is a .kiro.hook JSON file.
{
"name": "Test Synchronization",
"description": "Update tests when implementation changes",
"version": "1",
"when": {
"type": "fileEdited",
"patterns": ["src/components/**/*.tsx"]
},
"then": {
"type": "askAgent",
"prompt": "Implementation changed. Update tests."
}
}
Sources: packages/webapp/src/app/blog/kiro-hooks-automation/page.tsx:78-91
The structure is defined by when (the trigger) and then (the action).
This diagram shows the JSON structure for a Kiro hook, detailing the when and then clauses.
Sources: packages/webapp/src/app/blog/format-specifications-guide/page.tsx:608-632, packages/webapp/src/app/blog/kiro-hooks-automation/page.tsx:78-91
Best Practices for Hook Development
Writing robust hooks is critical, as they execute with your user permissions and can fail silently or break your workflow if not written carefully.
Sources: packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:43-45, 52-55
Security
- Validate All Input: Never trust the JSON input from
stdin. Always validate file paths and other parameters. Check that files exist and are within the project directory. - Quote Everything: File paths can contain spaces or special characters. Always wrap variables in double quotes (e.g.,
cat "$FILE") to prevent shell-splitting issues. - Block Sensitive Files: Explicitly block hooks from accessing sensitive files like
.env,.pem,.key, or.git/*. APreToolUsehook is the ideal place for this.
Sources: packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:58-102
Reliability
- Handle Missing Tools: Check if a required command-line tool (like
prettierorjq) is installed before attempting to use it. Exit gracefully if it's missing. - Set Reasonable Timeouts: Long-running hooks can block the AI assistant. Set a
timeoutin the hook configuration (e.g., 10000ms for 10 seconds). For slow tasks, run them as background processes ((eslint "$FILE" &)). - Log Failures: Redirect error output (
stderr) to a log file. Do not log tostdout, as this can be misinterpreted as hook output by the AI.
Sources: packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:120-181
Performance
- Keep Hooks Fast: Hooks are blocking operations. A slow hook makes the AI feel sluggish.
- Use Specific Matchers: Avoid broad matchers like
*. Target only the specific tools or file patterns you care about (e.g.,matcher: "Write"instead ofmatcher: "Edit|Write"if you only care about new files). - Run Slow Tasks in the Background: For non-critical tasks like linting or running tests, detach the process from the hook script so it doesn't block the main thread.
Sources: packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:188-228
Testing and Publishing
Manual Testing
Before publishing, test your hook script manually by piping sample JSON input to it. This allows you to verify its logic and exit codes without needing a full AI session.
# Create a test input file
echo '{
"input": {
"file_path": "/path/to/your/test file.ts"
}
}' | ./my-hook.sh
# Check the exit code
echo $?
Test with edge cases like file paths with spaces, Unicode characters, deep paths, and empty or invalid input.
Sources: packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:313-346
Publishing with PRPM
PRPM standardizes the process of creating and sharing hooks.
- Initialize a new hook package:
prpm init # Choose format: claude, subtype: hook - Define the hook: Write your hook logic in the generated package file. For Claude hooks, this is a JSON file containing the hook configuration.
- Publish:
prpm publish
Once published, anyone can install your hook with a single command, and PRPM will automatically merge it into their local configuration.
Sources: packages/webapp/src/app/blog/claude-hooks-support/page.tsx:173-201
Summary
Custom hooks provide a powerful mechanism for automating development workflows and enforcing coding standards within AI-assisted environments. By following security, reliability, and performance best practices, you can create robust hooks that enhance productivity. PRPM further streamlines this process by offering a standardized way to package, distribute, and manage hooks, making them accessible to the wider development community.
Sources: packages/webapp/src/app/blog/claude-hooks-best-practices/page.tsx:372-376, packages/webapp/src/app/blog/claude-hooks-support/page.tsx:110-113