PreToolUse & PostToolUse Hooks
Control and monitor tool execution with PreToolUse and PostToolUse hooks.
PreToolUse Hook
Executes before each tool call. Can approve, deny, or request user confirmation.
Signature
import type { PreToolUseHookInput } from '@anthropic-ai/claude-agent-sdk';
export async function PreToolUse(
input: PreToolUseHookInput,
toolUseID: string,
options: { signal: AbortSignal }
): Promise<{
decision?: 'approve' | 'block';
systemMessage?: string;
hookSpecificOutput?: {
hookEventName: 'PreToolUse';
permissionDecision?: 'allow' | 'deny' | 'ask';
permissionDecisionReason?: string;
updatedInput?: Record<string, unknown>;
};
}>
Use Cases
- Block dangerous operations
- Require confirmation for sensitive tools
- Log tool usage
- Validate tool inputs
Example: Block Dangerous Commands
export async function PreToolUse(input: PreToolUseHookInput) {
if (input.tool_name === 'Bash') {
const cmd = input.tool_input?.command as string;
const dangerous = [
/rm\s+-rf\s+\//,
/dd\s+if=/,
/mkfs/
];
if (dangerous.some(pattern => pattern.test(cmd))) {
return {
decision: 'deny',
message: 'Dangerous command blocked'
};
}
}
return { decision: 'approve' };
}
Example: Require Confirmation
export async function PreToolUse(input: PreToolUseHookInput) {
// Require confirmation for Write tool
if (input.tool_name === 'Write') {
return {
decision: 'pending',
message: `Create file: ${input.tool_input?.file_path}`
};
}
// Auto-approve Read
return { decision: 'approve' };
}
PostToolUse Hook
Executes after each tool call. Can inspect results and log outcomes.
Signature
import type { PostToolUseHookInput } from '@anthropic-ai/claude-agent-sdk';
export async function PostToolUse(
input: PostToolUseHookInput,
toolUseID: string,
options: { signal: AbortSignal }
): Promise<{
hookSpecificOutput?: {
hookEventName: 'PostToolUse';
additionalContext?: string;
updatedMCPToolOutput?: unknown;
};
}>
Use Cases
- Audit logging
- Collect metrics
- Track tool usage
- Error monitoring
Example: Audit Log
import { appendFileSync } from 'fs';
export async function PostToolUse(input: PostToolUseHookInput) {
const log = {
timestamp: new Date().toISOString(),
tool: input.tool_name,
input: input.tool_input,
success: !input.tool_response?.error
};
appendFileSync('audit.log', JSON.stringify(log) + '\n');
return {};
}
Example: Metrics Collection
const metrics = new Map<string, number>();
export async function PostToolUse(input: PostToolUseHookInput) {
const count = metrics.get(input.tool_name) || 0;
metrics.set(input.tool_name, count + 1);
console.log('[Metrics]', Array.from(metrics.entries()));
return {};
}
Combined Example
export async function PreToolUse(input: PreToolUseHookInput) {
console.log(`[PreToolUse] ${input.tool_name}`);
// Security checks
if (input.tool_name === 'Bash') {
const cmd = input.tool_input?.command;
if (cmd?.includes('rm -rf')) {
return { decision: 'deny', message: 'Blocked' };
}
}
return { decision: 'approve' };
}
export async function PostToolUse(input: PostToolUseHookInput) {
console.log(`[PostToolUse] ${input.tool_name} completed`);
// Log errors
if (input.tool_response?.error) {
console.error('[Error]', input.tool_response.error);
}
return {};
}