Claude Code has 4 hook handler types (command, prompt, agent, http) and 21 lifecycle events. Most developers default to command hooks on PreToolUse. This decision guide helps you pick the right type for the right event, and tells you which 3 to implement first. Two configs. Same goal: block a force push to main. Different reliability: # Command hook (deterministic, <5ms) COMMAND = $( jq -r '.tool_input.command // empty' < /dev/stdin ) if echo " $COMMAND " | grep -qE 'git push.*(--force|-f).*main' ; then echo "BLOCKED: force push to main" > &2 exit 2 fi Enter fullscreen mode Exit fullscreen mode // Prompt hook (non-deterministic, 300-2000 ms) { "type" : "prompt" , "prompt" : "Block this if it looks like a force push to a production branch" } Enter fullscreen mode Exit fullscreen mode The command hook is 5 lines of bash. It runs in under 5ms. It catches every git push --force main without exception. The prompt hook calls an LLM. It takes 300-2000ms.…