claude-flow
Version:
Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration
533 lines (428 loc) • 13.2 kB
Markdown
# V3 Hooks System
Extensible hook points for tool execution, file operations, and lifecycle events. Integrates with the event bus for coordination and monitoring.
## Features
- **26 Hook Events**: Comprehensive lifecycle hooks for tools, files, commands, sessions, agents, tasks, memory, and errors
- **Priority-Based Execution**: Control execution order with 5 priority levels
- **Timeout Handling**: Configurable timeouts per hook with graceful degradation
- **Error Recovery**: Continue execution on errors or abort based on configuration
- **Context Modification**: Hooks can modify context for downstream hooks
- **Parallel & Sequential Execution**: Execute hooks in parallel or chain them sequentially
- **Event Bus Integration**: Emit coordination events to the event bus
- **Statistics Tracking**: Monitor hook performance and execution metrics
## Installation
```typescript
import {
createHookRegistry,
createHookExecutor,
HookEvent,
HookPriority
} from '@claude-flow/shared/hooks';
```
## Quick Start
### 1. Create Registry and Executor
```typescript
import { createHookRegistry, createHookExecutor } from '@claude-flow/shared/hooks';
import { createEventBus } from '@claude-flow/shared/core';
const registry = createHookRegistry();
const eventBus = createEventBus();
const executor = createHookExecutor(registry, eventBus);
```
### 2. Register a Hook
```typescript
const hookId = registry.register(
HookEvent.PreToolUse,
async (context) => {
console.log(`About to use tool: ${context.tool?.name}`);
// Validate tool parameters
if (!context.tool?.parameters) {
return {
success: false,
error: new Error('Missing tool parameters'),
abort: true // Abort tool execution
};
}
return { success: true };
},
HookPriority.High,
{
name: 'Tool Validation Hook',
timeout: 5000
}
);
```
### 3. Execute Hooks
```typescript
const result = await executor.execute(
HookEvent.PreToolUse,
{
event: HookEvent.PreToolUse,
timestamp: new Date(),
tool: {
name: 'Read',
parameters: { path: '/path/to/file.ts' },
category: 'file'
}
}
);
if (result.success) {
console.log(`✓ All hooks passed (${result.hooksExecuted} executed)`);
} else {
console.log(`✗ Hook execution failed: ${result.hooksFailed} failures`);
}
```
## Hook Events
### Tool Execution
```typescript
HookEvent.PreToolUse // Before any tool is used
HookEvent.PostToolUse // After tool execution completes
```
### File Operations
```typescript
HookEvent.PreRead // Before reading a file
HookEvent.PostRead // After reading a file
HookEvent.PreWrite // Before writing a file
HookEvent.PostWrite // After writing a file
HookEvent.PreEdit // Before editing a file
HookEvent.PostEdit // After editing a file
```
### Command Execution
```typescript
HookEvent.PreCommand // Before executing bash command
HookEvent.PostCommand // After command execution
```
### Session Lifecycle
```typescript
HookEvent.SessionStart // When session starts
HookEvent.SessionEnd // When session ends
HookEvent.SessionPause // When session is paused
HookEvent.SessionResume // When session resumes
```
### Agent Lifecycle
```typescript
HookEvent.PreAgentSpawn // Before spawning agent
HookEvent.PostAgentSpawn // After agent spawned
HookEvent.PreAgentTerminate // Before terminating agent
HookEvent.PostAgentTerminate // After agent terminated
```
### Task Lifecycle
```typescript
HookEvent.PreTaskExecute // Before task execution
HookEvent.PostTaskExecute // After task execution
HookEvent.PreTaskComplete // Before marking task complete
HookEvent.PostTaskComplete // After task completed
```
### Memory Operations
```typescript
HookEvent.PreMemoryStore // Before storing memory
HookEvent.PostMemoryStore // After storing memory
HookEvent.PreMemoryRetrieve // Before retrieving memory
HookEvent.PostMemoryRetrieve // After retrieving memory
```
### Error Handling
```typescript
HookEvent.OnError // When error occurs
HookEvent.OnWarning // When warning occurs
```
## Hook Priorities
Control execution order with priority levels:
```typescript
HookPriority.Critical = 1000 // Execute first
HookPriority.High = 500
HookPriority.Normal = 0 // Default
HookPriority.Low = -500
HookPriority.Lowest = -1000 // Execute last
```
## Advanced Usage
### Context Modification
Hooks can modify context for downstream hooks:
```typescript
registry.register(
HookEvent.PreCommand,
async (context) => {
// Add risk assessment to context
const isDestructive = context.command?.command.includes('rm -rf');
return {
success: true,
data: {
metadata: {
...context.metadata,
riskLevel: isDestructive ? 'high' : 'low'
}
}
};
},
HookPriority.High
);
// Later hook can access the risk level
registry.register(
HookEvent.PreCommand,
async (context) => {
if (context.metadata?.riskLevel === 'high') {
console.warn('⚠️ High-risk command detected!');
}
return { success: true };
},
HookPriority.Normal
);
```
### Abort Operations
Hooks can abort the operation:
```typescript
registry.register(
HookEvent.PreCommand,
async (context) => {
const isDangerous = context.command?.command.includes('format c:');
if (isDangerous) {
return {
success: false,
abort: true, // Prevent command execution
error: new Error('Dangerous command blocked by security hook')
};
}
return { success: true };
},
HookPriority.Critical
);
```
### Timeout Handling
Configure timeouts per hook:
```typescript
registry.register(
HookEvent.PreToolUse,
async (context) => {
// Expensive operation
await analyzeCodeComplexity(context.tool?.parameters);
return { success: true };
},
HookPriority.Normal,
{
timeout: 3000 // 3 second timeout
}
);
```
### Parallel Execution
Execute hooks for multiple events in parallel:
```typescript
const results = await executor.executeParallel(
[HookEvent.PreRead, HookEvent.PreWrite, HookEvent.PreEdit],
[
{ event: HookEvent.PreRead, timestamp: new Date(), file: { path: 'a.ts', operation: 'read' } },
{ event: HookEvent.PreWrite, timestamp: new Date(), file: { path: 'b.ts', operation: 'write' } },
{ event: HookEvent.PreEdit, timestamp: new Date(), file: { path: 'c.ts', operation: 'edit' } }
],
{ maxParallel: 3 }
);
```
### Sequential Execution with Context Chaining
Execute hooks sequentially, passing context modifications:
```typescript
const result = await executor.executeSequential(
[
HookEvent.PreTaskExecute,
HookEvent.PostTaskExecute,
HookEvent.PreTaskComplete,
HookEvent.PostTaskComplete
],
{
event: HookEvent.PreTaskExecute,
timestamp: new Date(),
task: { id: 'task-1', description: 'Process data' }
}
);
// result.finalContext contains all modifications from all hooks
```
## Hook Statistics
Track hook performance:
```typescript
const stats = registry.getStats();
console.log(`Total hooks: ${stats.totalHooks}`);
console.log(`Total executions: ${stats.totalExecutions}`);
console.log(`Total failures: ${stats.totalFailures}`);
console.log(`Average execution time: ${stats.avgExecutionTime}ms`);
// Hooks by event type
for (const [event, count] of Object.entries(stats.byEvent)) {
console.log(`${event}: ${count} hooks`);
}
```
## Integration with Event Bus
The executor emits coordination events to the event bus:
```typescript
eventBus.on('hooks:pre-execute', (event) => {
console.log(`Executing ${event.payload.hookCount} hooks for ${event.payload.event}`);
});
eventBus.on('hooks:post-execute', (event) => {
console.log(`Completed in ${event.payload.totalExecutionTime}ms`);
});
eventBus.on('hooks:error', (event) => {
console.error(`Hook ${event.payload.hookId} failed:`, event.payload.error);
});
```
## Best Practices
### 1. Use Appropriate Priorities
- `Critical`: Security checks, validation that must happen first
- `High`: Important preprocessing (risk assessment, logging)
- `Normal`: Standard business logic
- `Low`: Optional enhancements, metrics
- `Lowest`: Cleanup, final logging
### 2. Handle Errors Gracefully
```typescript
registry.register(
HookEvent.PreToolUse,
async (context) => {
try {
await performValidation(context);
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error(String(error)),
continueChain: true // Allow other hooks to run
};
}
}
);
```
### 3. Keep Hooks Fast
Hooks should be fast (<100ms). For expensive operations:
```typescript
registry.register(
HookEvent.PostToolUse,
async (context) => {
// Queue expensive work for background processing
backgroundQueue.add({
type: 'analyze-tool-usage',
context
});
return { success: true };
},
HookPriority.Low
);
```
### 4. Use Descriptive Names
```typescript
registry.register(
HookEvent.PreCommand,
handler,
HookPriority.Critical,
{
name: 'Security: Prevent Destructive Commands',
metadata: {
purpose: 'Block dangerous shell commands',
blockedPatterns: ['rm -rf /', 'format c:']
}
}
);
```
## Example: Pre-Edit Hook for Learning
```typescript
import { HookEvent, HookPriority } from '@claude-flow/shared/hooks';
// Register pre-edit hook for context retrieval
registry.register(
HookEvent.PreEdit,
async (context) => {
const filePath = context.file?.path;
if (!filePath) {
return { success: true };
}
// Get similar past edits from ReasoningBank
const similarEdits = await reasoningBank.searchPatterns({
task: `Edit file: ${filePath}`,
k: 5,
minReward: 0.85
});
console.log(`📚 Found ${similarEdits.length} similar past edits`);
return {
success: true,
data: {
metadata: {
...context.metadata,
learningContext: similarEdits,
editCount: similarEdits.length
}
}
};
},
HookPriority.High,
{
name: 'Learning: Pre-Edit Context Retrieval',
timeout: 2000
}
);
// Register post-edit hook for learning storage
registry.register(
HookEvent.PostEdit,
async (context) => {
const success = context.metadata?.success ?? true;
const filePath = context.file?.path;
if (!filePath) {
return { success: true };
}
// Store edit pattern for future learning
await reasoningBank.storePattern({
sessionId: context.session?.id || 'unknown',
task: `Edit file: ${filePath}`,
input: context.file?.previousContent || '',
output: context.file?.content || '',
reward: success ? 0.9 : 0.3,
success,
tokensUsed: estimateTokens(context.file?.content),
latencyMs: context.metadata?.executionTime || 0
});
return { success: true };
},
HookPriority.Normal,
{
name: 'Learning: Post-Edit Pattern Storage',
timeout: 1000
}
);
```
## API Reference
### HookRegistry
- `register(event, handler, priority, options)` - Register a hook
- `unregister(hookId)` - Unregister a hook
- `unregisterAll(event?)` - Unregister all hooks for an event
- `getHandlers(event, includeDisabled)` - Get handlers for an event
- `getHook(hookId)` - Get hook by ID
- `enable(hookId)` - Enable a hook
- `disable(hookId)` - Disable a hook
- `listHooks(filter)` - List all hooks with optional filter
- `getEventTypes()` - Get all event types with hooks
- `count(event?)` - Get hook count
- `getStats()` - Get execution statistics
- `resetStats()` - Reset statistics
- `has(hookId)` - Check if hook exists
- `clear()` - Clear all hooks
### HookExecutor
- `execute(event, context, options)` - Execute hooks for an event
- `executeWithTimeout(event, context, timeout)` - Execute with timeout
- `executeParallel(events, contexts, options)` - Execute multiple events in parallel
- `executeSequential(events, initialContext, options)` - Execute sequentially with context chaining
- `setEventBus(eventBus)` - Set event bus for coordination
- `getRegistry()` - Get hook registry
## Testing
Run the test suite:
```bash
cd /workspaces/claude-flow/v3/@claude-flow/shared
npm test -- hooks.test.ts
```
All 23 tests pass:
- 11 registry tests
- 12 executor tests
## File Structure
```
v3/@claude-flow/shared/src/hooks/
├── types.ts # Type definitions (~150 lines)
├── registry.ts # Hook registry (~200 lines)
├── executor.ts # Hook executor (~250 lines)
├── index.ts # Main exports
├── hooks.test.ts # Test suite (~20 tests)
└── README.md # This file
```
## Integration Points
- **Event Bus**: Emits coordination events (`hooks:pre-execute`, `hooks:post-execute`, `hooks:error`)
- **Event Store**: Can log hook executions for audit trail (ADR-007)
- **ReasoningBank**: Hooks can integrate with learning system for context retrieval and pattern storage
- **Security**: Critical hooks can enforce security policies (CVE-1, CVE-2, CVE-3)
## License
Part of Claude-Flow V3 - See main LICENSE file