A comprehensive TypeScript framework for building type-safe Claude Code hooks, built on top of the official @anthropic-ai/claude-code SDK for maximum compatibility and type safety.
Transform Claude Code hook development from manual shell scripting to type-safe, testable, maintainable TypeScript applications. Built directly on the official Claude Code SDK, this framework ensures full compatibility with all Claude Code features while providing a superior developer experience.
- π‘οΈ SDK Integration: Built on
@anthropic-ai/claude-codefor guaranteed compatibility - π Full Type Safety: Complete TypeScript types for all hooks and tools via the SDK
- π§ Multiple APIs: Function-based, Builder pattern, and Declarative approaches
- π Security: Built-in validators and environment-specific protections
- π§ͺ Testing: Complete mock framework and testing utilities
- β‘ Performance: Fast, efficient hook execution with proper error handling
- π― Tool Scoping: Hooks can target specific tools or run universally
# Install core packages
bun add @carabiner/hooks-core @carabiner/types @carabiner/execution
# For development
bun add -d @carabiner/hooks-testing @carabiner/hooks-validatorsAll packages are available on npm under the @carabiner scope:
- Core:
@carabiner/hooks-core- Core hook functionality with SDK integration - Types:
@carabiner/types- TypeScript type definitions - Execution:
@carabiner/execution- Hook execution engine - Testing:
@carabiner/hooks-testing- Testing utilities - Validators:
@carabiner/hooks-validators- Security validators - Registry:
@carabiner/hooks-registry- Pre-built hooks collection
The core package includes and re-exports all necessary types from @anthropic-ai/claude-code, ensuring you have access to the full Claude Code type system.
packages/
βββ types/ # Core type definitions
βββ protocol/ # Communication protocol
βββ execution/ # Hook executor
βββ hooks-core/ # Core functionality
βββ hooks-cli/ # CLI tool
βββ hooks-config/ # Configuration management
βββ hooks-testing/ # Testing utilities
βββ hooks-validators/ # Validation utilities
βββ plugins/ # Plugin collection
βββ registry/ # Hook registry
βββ examples/ # Example hooks
βββ error-management/ # Error handling
New to Carabiner? Start with our Hello World Tutorial - build your first hook in under 5 minutes!
import { createHook, HookResults } from '@carabiner/hooks-core';
// Create a simple hook that runs before any tool
const myFirstHook = createHook.preToolUse(async (context) => {
console.log(`π― Tool ${context.tool} is about to run!`);
return HookResults.success();
});
// That's it! Your hook is ready to useimport { createHook } from '@carabiner/hooks-core';
const myHook = createHook('PreToolUse', async (context) => {
const { toolName, toolInput } = context;
// Block dangerous operations
if (toolName === 'Bash' && toolInput.command?.includes('rm -rf')) {
return {
success: false,
message: 'Dangerous command blocked'
};
}
return { success: true };
});
// Register and use
registry.register(myHook);import { HookBuilder } from '@carabiner/hooks-core';
const securityHook = new HookBuilder()
.event('PreToolUse')
.name('security-validator')
.description('Validates file operations for security')
.timeout(3000)
.handler(async (context) => {
// Security validation logic
return { success: true };
})
.build();import { defineHooks } from '@carabiner/hooks-core';
const hooks = defineHooks({
'pre-tool-use': [
{
name: 'rate-limiter',
handler: './hooks/rate-limiter.ts',
config: { maxRequests: 100 }
}
],
'post-tool-use': [
{
name: 'markdown-formatter',
handler: '@carabiner/hooks-registry/markdown-formatter'
}
]
});import { createFileAccessValidator } from '@carabiner/hooks-validators';
const protectSensitive = createFileAccessValidator({
protectedPaths: ['.env', '**/*.key', '**/*.pem'],
protectedPatterns: [/password/i, /secret/i],
allowedOperations: ['read'],
environments: ['production']
});
registry.register('PreToolUse', protectSensitive);import { createGitSafetyValidator } from '@carabiner/hooks-validators';
const gitSafety = createGitSafetyValidator({
protectMainBranch: true,
requireConventionalCommits: true,
blockForceCommands: true
});import { test, expect } from 'bun:test';
import { createMockContext, MockRegistry } from '@carabiner/hooks-testing';
test('security hook blocks dangerous commands', async () => {
const context = createMockContext({
event: 'PreToolUse',
toolName: 'Bash',
toolInput: { command: 'rm -rf /' }
});
const result = await securityHook(context);
expect(result.success).toBe(false);
expect(result.message).toContain('blocked');
});const mockRegistry = new MockRegistry();
mockRegistry.register('PreToolUse', myHook);
// Test with deterministic execution
const results = await mockRegistry.execute('PreToolUse', context);
expect(results.all()).toHaveLength(1);{
"hooks": {
"PreToolUse": {
"timeout": 5000,
"handlers": ["security-validator", "rate-limiter"]
},
"PostToolUse": {
"handlers": ["markdown-formatter", "test-runner"]
}
}
}const config = {
development: {
hooks: ['debug-logger', 'performance-monitor']
},
production: {
hooks: ['security-validator', 'audit-logger']
}
};The @carabiner/hooks-registry package includes ready-to-use hooks:
Automatically formats markdown files using markdownlint or prettier.
import { markdownFormatterHook } from '@carabiner/hooks-registry';
registry.register('PostToolUse', markdownFormatterHook);Validates file operations and prevents access to sensitive files.
import { securityScannerHook } from '@carabiner/hooks-registry';
registry.register('PreToolUse', securityScannerHook);Automatically runs tests after code changes.
import { testRunnerHook } from '@carabiner/hooks-registry';
registry.register('PostToolUse', testRunnerHook);Carabiner is built directly on top of the official @anthropic-ai/claude-code SDK, ensuring full compatibility with all Claude Code features:
// Import SDK types directly
import type {
HookInput,
HookJSONOutput,
PreToolUseHookInput,
BashInput
} from '@carabiner/hooks-core';
// All SDK types are re-exported for convenience
const handler: HookCallback = async (input, toolUseID, options) => {
if (input.hook_event_name === 'PreToolUse') {
const toolInput = input as PreToolUseHookInput;
// Full type safety with SDK types
return {
continue: true,
systemMessage: `Processing ${toolInput.tool_name}...`
};
}
return { continue: true };
};import type { HookHandler, HookContext, HookResult } from '@carabiner/hooks-core';
// Full type safety and IntelliSense
const typedHook: HookHandler<PreToolUseHookInput> = async (input, toolUseID, options) => {
// TypeScript knows exact input structure from SDK
const { tool_name, tool_input } = input;
return { continue: true };
};All hook events are defined by the Claude Code SDK:
- PreToolUse: Before tool execution
- PostToolUse: After tool completion
- UserPromptSubmit: When user submits a prompt
- SessionStart: When session begins
- SessionEnd: When session ends
- Stop: When execution stops
- SubagentStop: When subagent stops
- PreCompact: Before compacting history
- Notification: For notifications
Use the Carabiner CLI to discover, install, run, and publish hooks:
# List and run hooks
carabiner list
carabiner bash-command-validator
# Discover and install
carabiner browse
carabiner add bash-command-validator
# Publish a hook
carabiner publish --npmThe CLI is available via Node (ESM) or as a Bun-compiled standalone binary. See Quickstart for setup.
Carabiner is designed from the ground up for full Claude Code compatibility, built directly on the official @anthropic-ai/claude-code SDK.
- π‘οΈ SDK Foundation: Built on
@anthropic-ai/claude-codefor guaranteed compatibility - π All Hook Events: Supports all 9 Claude Code hook events with full type safety
- π§ Tool Integration: First-class support for all Claude Code tools + MCP tools
- π― Exit Code Semantics: Proper handling of Claude Code's exit code requirements
- π‘ JSON Protocol: Native support for Claude Code's stdin/stdout JSON protocol
- π Permission System: Rich permission controls with detailed feedback to Claude
Transform manual shell scripts into type-safe TypeScript hooks:
Before (Shell Script):
#!/bin/bash
# Limited context, error-prone
if [[ "$TOOL_INPUT_COMMAND" == *"rm -rf"* ]]; then
echo "Dangerous command blocked!"
exit 1
fiAfter (Carabiner Hook):
#!/usr/bin/env bun
import { runClaudeHook, HookResults } from '@carabiner/hooks-core';
runClaudeHook(async (context) => {
if (context.toolName === 'Bash') {
const { command } = context.toolInput as { command: string };
if (command.includes('rm -rf')) {
return HookResults.block('Dangerous command blocked!');
}
}
return HookResults.success('Command validated');
});Built-in support for Model Context Protocol (MCP) tools:
import { isMCPToolName, validateMCPToolName } from '@carabiner/hooks-core';
runClaudeHook(async (context) => {
// Detect and handle MCP tools
if (isMCPToolName(context.toolName)) {
const { provider, toolName } = validateMCPToolName(context.toolName);
console.log(`MCP Tool: ${provider}::${toolName}`);
// Provider-specific validation
return validateMCPTool(provider, toolName, context.toolInput);
}
return HookResults.success('Standard tool validated');
});Full support for all Claude Code hook events:
| Event | Purpose | Carabiner Support |
|---|---|---|
PreToolUse |
Validate/block tool execution | β Full support + type safety |
PostToolUse |
Process tool results | β Access to tool response |
SessionStart |
Initialize session | β Context injection |
SessionEnd |
Cleanup session | β Resource management |
UserPromptSubmit |
Process user input | β Input validation |
Stop |
Handle execution stop | β Graceful shutdown |
SubagentStop |
Handle subagent stop | β Subagent management |
PreCompact |
Before history compaction | β Data archival |
Notification |
Handle notifications | β Event processing |
- Install Carabiner:
bun add @carabiner/hooks-core - Convert scripts to TypeScript using
runClaudeHook() - Update configuration to point to new hooks
- Test thoroughly with real Claude Code integration
See our Migration Guide for detailed instructions.
- Basic PreToolUse Hook - Security validation examples
- Permission Control - Advanced permission system
- MCP Integration - MCP tool handling
- Context Injection - SessionStart context setup
- Quickstart
- Claude Code Migration Guide
- API Reference
- Configuration Guide
- Testing Guide
- Troubleshooting Guide
- Example Hooks
- Claude Code Examples
- Registry + CLI Guide
We welcome contributions! Please see our Contributing Guide for details.
# Clone repository
git clone https://github.com/outfitter-dev/carabiner.git
cd carabiner
# Install dependencies
bun install
# Run tests
bun test
# Build all packages
turbo buildMIT Β© Outfitter
Built with modern tools and best practices:
- Bun - Fast JavaScript runtime
- TypeScript - Type safety
- Turbo - Monorepo management
- Ultracite - Code quality