Skip to main content

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 {};
}