Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/affaan-m/everything-claude-code/llms.txt

Use this file to discover all available pages before exploring further.

Hooks are shell commands that receive tool input as JSON on stdin and must output JSON on stdout. You can create custom hooks to enforce project-specific rules and automate repetitive checks.

Basic Hook Structure

my-hook.js
let data = '';
process.stdin.on('data', chunk => data += chunk);
process.stdin.on('end', () => {
  const input = JSON.parse(data);

  // Access tool info
  const toolName = input.tool_name;        // "Edit", "Bash", "Write", etc.
  const toolInput = input.tool_input;      // Tool-specific parameters
  const toolOutput = input.tool_output;    // Only available in PostToolUse

  // Warn (non-blocking): write to stderr
  console.error('[Hook] Warning message shown to Claude');

  // Block (PreToolUse only): exit with code 2
  // process.exit(2);

  // Always output the original data to stdout
  console.log(data);
});

Exit Codes

0
success
Success — continue execution
2
block
Block the tool call (PreToolUse only)
other
error
Error — logged but does not block

Hook Input Schema

interface HookInput {
  tool_name: string;          // "Bash", "Edit", "Write", "Read", etc.
  tool_input: {
    command?: string;         // Bash: the command being run
    file_path?: string;       // Edit/Write/Read: target file
    old_string?: string;      // Edit: text being replaced
    new_string?: string;      // Edit: replacement text
    content?: string;         // Write: file content
  };
  tool_output?: {             // PostToolUse only
    output?: string;          // Command/tool output
  };
}

Common Hook Recipes

Warn About TODO Comments

{
  "matcher": "Edit",
  "hooks": [{
    "type": "command",
    "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const ns=i.tool_input?.new_string||'';if(/TODO|FIXME|HACK/.test(ns)){console.error('[Hook] New TODO/FIXME added - consider creating an issue')}console.log(d)})\""
  }],
  "description": "Warn when adding TODO/FIXME comments"
}

Block Large File Creation

{
  "matcher": "Write",
  "hooks": [{
    "type": "command",
    "command": "node block-large-files.js"
  }],
  "description": "Block creation of files larger than 800 lines"
}

Auto-Format Python Files with Ruff

{
  "matcher": "Edit",
  "hooks": [{
    "type": "command",
    "command": "node format-python.js"
  }],
  "description": "Auto-format Python files with ruff after edits"
}

Require Test Files Alongside New Source Files

{
  "matcher": "Write",
  "hooks": [{
    "type": "command",
    "command": "node require-tests.js"
  }],
  "description": "Remind to create tests when adding new source files"
}

Async Hooks

For hooks that should not block the main flow (e.g., background analysis):
{
  "type": "command",
  "command": "node my-slow-hook.js",
  "async": true,
  "timeout": 30
}
Async hooks run in the background. They cannot block tool execution.

Example: Background Build Analysis

build-analysis.js
const { exec } = require('child_process');

let data = '';
process.stdin.on('data', chunk => data += chunk);
process.stdin.on('end', () => {
  const input = JSON.parse(data);
  const command = input.tool_input?.command || '';
  
  // Check if it's a build command
  if (/(npm run build|pnpm build|yarn build)/.test(command)) {
    console.error('[Hook] Build completed - async analysis running in background');
    
    // Run analysis in background (async hook)
    exec('node analyze-bundle.js', (error, stdout, stderr) => {
      if (error) {
        console.error('[Hook] Analysis failed:', error.message);
      } else {
        console.error('[Hook] Bundle analysis complete');
      }
    });
  }
  
  console.log(data);
});

Customizing Hooks

Disabling a Hook

Remove or comment out the hook entry in hooks.json. If installed as a plugin, override in your ~/.claude/settings.json:
~/.claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [],
        "description": "Override: allow all .md file creation"
      }
    ]
  }
}

Environment Variables

Use environment variables for hook configuration:
const threshold = parseInt(process.env.MAX_FILE_LINES || '800', 10);
const enableCheck = process.env.ENABLE_TEST_CHECK === 'true';

Cross-Platform Notes

All hooks should use Node.js (node -e or node script.js) for maximum compatibility across Windows, macOS, and Linux. Avoid bash-specific syntax in hooks.

File Path Handling

const path = require('path');

// WRONG: Unix-specific paths
if (filePath.includes('src/')) { ... }

// CORRECT: Cross-platform path handling
if (filePath.includes(path.join('src', ''))) { ... }
// OR use regex that matches both separators
if (/[\\/]src[\\/]/.test(filePath)) { ... }