CC-101 · Module 4

Stop Hooks Deep Dive

4 min read

Stop hooks are the most powerful automation pattern in Claude Code — and the one most people never set up. A stop hook fires every time Claude finishes a task and is waiting for your next input. The magic: you can check if files were changed, run quality tools, feed errors back to Claude, and even auto-commit clean code — all without lifting a finger. John Linquist from egghead.io built a stop hook that creates a fully automated quality loop: Claude finishes → hook checks for file changes → runs TypeScript type checker → if errors exist, feeds them back to Claude as a blocking error → Claude fixes them → hook runs again → if clean, auto-commits.

// Simplified stop hook pattern
import type { HookInput } from '@anthropic-ai/claude-code';

// 1. Check if files were changed
const filesChanged = await checkGitDiff();
if (!filesChanged) return; // Nothing to check

// 2. Run quality checks (TypeScript, linting, etc.)
const errors = await runTypeCheck(); // bun type-check --quiet

// 3. If errors found, feed back to Claude
if (errors) {
  console.log(JSON.stringify({
    decision: 'block',
    reason: `Please fix TypeScript errors:\n${errors}`
  }));
  return;
}

// 4. If clean, auto-commit
console.log(JSON.stringify({
  decision: 'block', 
  reason: 'All checks pass. Please commit these changes.'
}));

Boris Chenry (creator of Claude Code) uses a simpler post-tool-use hook to auto-format after every file edit. The hook handles 'the last 10%' — formatting errors that would otherwise fail CI. Combined with a stop hook for type checking, you get a pipeline where Claude writes code → formatter cleans it → type checker validates it → Claude fixes any errors → clean commit. The entire quality loop runs without human intervention.