- Published on
Practical Hooks for AI-Assisted Development in Claude Code
- Authors

- Name
- Anablock
AI Insights & Innovations

Practical Hooks for AI-Assisted Development in Claude Code
Claude Code hooks can help address common weaknesses in AI-assisted development, particularly on larger projects. These hooks run automatically when Claude makes changes to your code, providing immediate feedback and preventing common issues.
TypeScript Type Checking Hook
One of the most useful hooks addresses a fundamental problem: when Claude modifies a function signature, it often doesn't update all the places where that function is called throughout your project.
For example, if you ask Claude to add a verbose parameter to a function in schema.ts, it will successfully update the function definition but miss the call site in main.ts. This creates type errors that Claude doesn't immediately catch.
The solution is a post-tool-use hook that runs the TypeScript compiler after every file edit:
- Runs
tsc --noEmitto check for type errors - Captures any errors found
- Feeds the errors back to Claude immediately
- Prompts Claude to fix the issues in other files
This hook works for any typed language where you can run a type checker. For untyped languages, you could implement similar functionality using automated tests instead.
Query Duplication Prevention Hook
In larger projects with many database queries, Claude sometimes creates duplicate functionality instead of reusing existing code. This is especially problematic when you give Claude complex, multi-step tasks that include database operations as just one component.
Consider a project structure with multiple query files, each containing many SQL functions. When you ask Claude to "create a Slack integration that alerts about orders pending longer than 3 days," it might write a new query instead of using the existing getPendingOrders() function.
The query duplication hook addresses this by implementing a review process:
- Triggers when Claude modifies files in the
./queriesdirectory - Launches a separate instance of Claude Code programmatically
- Asks the second instance to review the changes and check for similar existing queries
- If duplicates are found, provides feedback to the original Claude instance
- Prompts Claude to remove the duplicate and use the existing functionality
Implementation Considerations
Both hooks use the pre-tool-use or post-tool-use hook system. The TypeScript hook is relatively lightweight and runs quickly. The query duplication hook requires more resources since it launches a separate Claude instance for each review.
For the query hook, consider these trade-offs:
- Benefits: Cleaner codebase with less duplication
- Costs: Additional time and API usage for each query directory edit
- Recommendation: Only monitor critical directories to minimize overhead
The hooks use Claude's TypeScript SDK to programmatically interact with the AI. This allows you to create sophisticated workflows where one Claude instance can review and provide feedback on another's work.
Additional Hook Types
There are more hooks beyond the PreToolUse and PostToolUse hooks discussed above:
- Notification - Runs when Claude Code sends a notification, which occurs when Claude needs permission to use a tool, or after Claude Code has been idle for 60 seconds
- Stop - Runs when Claude Code has finished responding
- SubagentStop - Runs when a subagent (displayed as a "Task" in the UI) has finished
- PreCompact - Runs before a compact operation occurs, either manual or automatic
- UserPromptSubmit - Runs when the user submits a prompt, before Claude processes it
- SessionStart - Runs when starting or resuming a session
- SessionEnd - Runs when a session ends
Understanding Hook Input Variations
Here's the confusing part:
- The stdin input to your commands will change based upon the type of hook being executed (PreToolUse, PostToolUse, Notification, etc)
- The
tool_inputcontained in that will differ based upon the tool that was called (in the case of PreToolUse and PostToolUse hooks)
For example, here's a sample of stdin input to a PostToolUse hook watching for the TodoWrite tool:
{
"session_id": "9ecf22fa-edf8-4332-ae85-b6d5456eda64",
"transcript_path": "<path_to_transcript>",
"hook_event_name": "PostToolUse",
"tool_name": "TodoWrite",
"tool_input": {
"todos": [{ "content": "write a readme", "status": "pending", "priority": "medium", "id": "1" }]
},
"tool_response": {
"oldTodos": [],
"newTodos": [{ "content": "write a readme", "status": "pending", "priority": "medium", "id": "1" }]
}
}
And for comparison, here's an example of the input to a Stop hook:
{
"session_id": "af9f50b6-f042-4773-b3e2-c3a4814765ce",
"transcript_path": "<path_to_transcript>",
"hook_event_name": "Stop",
"stop_hook_active": false
}
As you can see, the stdin input to your command will differ significantly based upon the hook type and the matcher used. This can make writing hooks challenging - you might not know the exact structure of the input to your command!
Debugging Hook Input
To handle this challenge, try making a helper hook like this:
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "jq . > post-log.json"
}
]
}
]
Notice the provided command. It will write the input to this hook to the post-log.json file, which allows you to inspect exactly what would have been fed into your command! This makes it a lot easier for you to understand what data your command should inspect.
Extending These Concepts
These hooks demonstrate broader principles you can apply to your own projects:
- Use compiler/linter output to provide immediate feedback
- Implement code review processes using separate AI instances
- Focus monitoring on high-value directories where consistency matters most
- Balance automation benefits against performance costs
The key is identifying the specific pain points in your development workflow and creating targeted hooks that address those issues automatically.