Documentation Index Fetch the complete documentation index at: https://docs.prpm.dev/llms.txt
Use this file to discover all available pages before exploring further.
Claude Code Hooks
Claude Code hooks allow you to execute custom TypeScript logic in response to lifecycle events like session start, tool usage, and user prompts. Hooks are powerful automation tools that can enforce workflows, add context, or modify behavior.
New to hooks? Install the hook writer skill to help you create hooks:prpm install @prpm/typescript-hook-writer-skill
This skill teaches AI how to write TypeScript hooks with proper structure, best practices, and error handling.
What are Hooks?
Hooks are TypeScript functions that run automatically when specific events occur in Claude Code:
SessionStart : Run code when a new conversation begins
UserPromptSubmit : Intercept and modify user prompts
ToolUse : Monitor or block tool usage
Custom Events : Create your own hook types
Installation
From PRPM Registry
The easiest way to install hooks is from the PRPM registry:
# Install a specific hook package
prpm install @prpm/my-hook
# Install multiple hooks at once
prpm install @prpm/hook-one @prpm/hook-two
# Install a collection of related hooks
prpm install @prpm/workspace-hooks-collection
Manual Installation
You can also create hooks manually:
Create a TypeScript file in .claude/hooks/
Add a hook.json manifest file
Register the hook in prpm.json
Example structure:
.claude/hooks/my-hook/
├── hook.ts # TypeScript implementation
├── hook.json # Hook metadata
└── dist/ # Compiled JavaScript (generated)
Hook Structure
hook.json
Every hook needs a hook.json manifest:
{
"name" : "my-hook" ,
"version" : "1.0.0" ,
"description" : "My custom hook" ,
"type" : "SessionStart" ,
"enabled" : true ,
"config" : {
"timeout" : 5000
}
}
Fields:
Field Type Required Description
namestring Yes Hook name (kebab-case) versionstring Yes Semver version descriptionstring Yes What the hook does typestring Yes Hook event type enabledboolean Yes Whether hook is active configobject No Hook-specific configuration
hook.ts
Your TypeScript implementation:
import { SessionStartHook } from '@claude/hooks' ;
export default async function myHook ( context : SessionStartHook [ 'context' ]) : Promise < SessionStartHook [ 'result' ]> {
// Your hook logic here
return {
additionalContext: 'Extra context for Claude' ,
systemReminders: [ 'Important reminder for this session' ]
};
}
Hook Types
SessionStart
Runs when a new Claude Code session begins. Perfect for adding project-specific context or reminders.
Use Cases:
Load project configuration
Add coding standards reminders
Check git status
Load environment-specific context
Example:
import { SessionStartHook } from '@claude/hooks' ;
export default async function sessionStart (
context : SessionStartHook [ 'context' ]
) : Promise < SessionStartHook [ 'result' ]> {
const projectInfo = `
Project: ${ context . workingDirectory }
Git Branch: ${ context . gitBranch || 'none' }
` ;
return {
additionalContext: projectInfo ,
systemReminders: [
'Follow TypeScript strict mode' ,
'Write tests for all new features'
]
};
}
UserPromptSubmit
Intercepts user prompts before they reach Claude. Can modify, block, or add context to prompts.
Use Cases:
Add context automatically
Enforce prompt patterns
Block certain requests
Log user interactions
Example:
import { UserPromptSubmitHook } from '@claude/hooks' ;
export default async function promptSubmit (
context : UserPromptSubmitHook [ 'context' ]
) : Promise < UserPromptSubmitHook [ 'result' ]> {
const { userPrompt } = context ;
// Add context to bug-related prompts
if ( userPrompt . includes ( 'bug' ) || userPrompt . includes ( 'fix' )) {
return {
additionalContext: 'Check the error logs in /logs for details' ,
modifiedPrompt: ` ${ userPrompt } \n\n Reminder: Follow systematic debugging workflow`
};
}
return { status: 'continue' };
}
Monitors tool usage and can block dangerous operations.
Use Cases:
Prevent accidental deletions
Log tool usage
Require confirmation for dangerous operations
Enforce tool usage patterns
Example:
import { ToolUseHook } from '@claude/hooks' ;
export default async function toolUse (
context : ToolUseHook [ 'context' ]
) : Promise < ToolUseHook [ 'result' ]> {
const { toolName , toolInput } = context ;
// Block deletion of important files
if ( toolName === 'Edit' && toolInput . file_path ?. includes ( '/config/' )) {
return {
status: 'blocked' ,
message: 'Editing config files requires manual review'
};
}
return { status: 'continue' };
}
Registering Hooks
After creating a hook, register it in your prpm.json:
{
"name" : "my-project" ,
"packages" : [
{
"name" : "my-hook" ,
"version" : "1.0.0" ,
"description" : "My custom hook" ,
"format" : "claude" ,
"subtype" : "hook" ,
"files" : [
".claude/hooks/my-hook/hook.ts" ,
".claude/hooks/my-hook/hook.json" ,
".claude/hooks/my-hook/dist/hook.js"
]
}
]
}
Building Hooks
Hooks must be compiled from TypeScript to JavaScript before Claude Code can use them.
Automatic Building
Use the scripts field in your root prpm.json to automatically build hooks before publishing:
{
"name" : "my-project" ,
"scripts" : {
"prepublishOnly" : "cd .claude/hooks/my-hook && npm run build"
},
"packages" : [ ... ]
}
When you run prpm publish, the prepublishOnly script runs automatically, ensuring hooks are always built before publishing.
Manual Building
cd .claude/hooks/my-hook
npm run build # or: esbuild hook.ts --outfile=dist/hook.js --bundle --platform=node
Best Practices
1. Use prepublishOnly Scripts
Always use prepublishOnly to build hooks automatically:
{
"scripts" : {
"prepublishOnly" : "cd packages/hooks && npm run build"
}
}
This prevents publishing stale JavaScript and keeps your dist files in sync.
2. Keep Hooks Fast
Hooks run on every event - keep them performant:
// ✅ Good: Fast and simple
export default async function myHook ( context ) {
return { additionalContext: 'Quick context' };
}
// ❌ Bad: Slow and blocking
export default async function myHook ( context ) {
await fetchFromAPI (); // Blocks session start!
await processLargeFile (); // Too slow!
return { additionalContext: 'Slow context' };
}
3. Handle Errors Gracefully
Don’t let hook errors crash sessions:
export default async function myHook ( context ) {
try {
// Your hook logic
return { status: 'continue' };
} catch ( error ) {
console . error ( 'Hook error:' , error );
// Continue anyway - don't block the session
return { status: 'continue' };
}
}
4. Use TypeScript Strictly
Enable strict mode for type safety:
import { SessionStartHook } from '@claude/hooks' ;
// Fully typed hook
export default async function myHook (
context : SessionStartHook [ 'context' ]
) : Promise < SessionStartHook [ 'result' ]> {
// TypeScript catches errors before runtime
return {
additionalContext: context . workingDirectory // Type-safe!
};
}
5. Document Your Hooks
Add comments explaining what your hooks do:
/**
* SessionStart hook that loads project-specific coding standards.
*
* Reads .standards.json and adds rules to Claude's context.
* Falls back to defaults if file doesn't exist.
*/
export default async function loadStandards ( context ) {
// Implementation
}
Advanced Configuration
Conditional Hooks
Enable hooks only in certain conditions:
{
"name" : "production-hook" ,
"type" : "SessionStart" ,
"enabled" : true ,
"config" : {
"enabledEnvironments" : [ "production" ],
"enabledBranches" : [ "main" , "release/*" ]
}
}
Hook Priorities
Control hook execution order with priorities:
{
"name" : "early-hook" ,
"type" : "SessionStart" ,
"priority" : 100
}
Higher priority = runs first.
Shared Configuration
Use config to share settings between hook code and Claude:
{
"name" : "my-hook" ,
"config" : {
"apiEndpoint" : "https://api.example.com" ,
"maxRetries" : 3
}
}
Access in your hook:
export default async function myHook ( context ) {
const { apiEndpoint , maxRetries } = context . hookConfig ;
// Use config values
}
Troubleshooting
Hook Not Running
Check:
Is enabled: true in hook.json?
Is the hook registered in prpm.json?
Is dist/hook.js compiled and up to date?
Does Claude Code have permission to read the file?
Build Errors
Common issues:
Missing dependencies: Run npm install in the hook directory
TypeScript errors: Check your type definitions
Import errors: Verify @claude/hooks is installed
Solutions:
Move slow operations outside hooks
Cache expensive computations
Use async operations carefully
Set timeout in hook.json config
Examples
Workspace Standards Hook
import { SessionStartHook } from '@claude/hooks' ;
import { readFile } from 'fs/promises' ;
export default async function workspaceStandards (
context : SessionStartHook [ 'context' ]
) : Promise < SessionStartHook [ 'result' ]> {
try {
const standards = await readFile ( '.standards.json' , 'utf-8' );
const parsed = JSON . parse ( standards );
return {
systemReminders: parsed . reminders || [],
additionalContext: `Workspace standards loaded: ${ parsed . name } `
};
} catch {
return {
systemReminders: [ 'Follow project best practices' ]
};
}
}
Git Branch Reminder
import { SessionStartHook } from '@claude/hooks' ;
export default async function gitBranchReminder (
context : SessionStartHook [ 'context' ]
) : Promise < SessionStartHook [ 'result' ]> {
const { gitBranch } = context ;
if ( gitBranch === 'main' || gitBranch === 'master' ) {
return {
systemReminders: [
'⚠️ You are on the main branch!' ,
'Consider creating a feature branch for changes'
]
};
}
return { status: 'continue' };
}
Next Steps
Publishing Hooks Share your hooks with others
Hook Writer Skill Install the hook writer skill to help create hooks prpm install @prpm/typescript-hook-writer-skill