Claude Code Hooks let you block dangerous AI agent commands, log every action, and get notifications when tasks complete. Five hook types give you programmable control over your agent's workflow—turning AI coding from automated chaos into supervised precision.
Jack Dorsey built a messaging app that ditches the internet entirely. Bitchat runs on Bluetooth networks within 30 meters, needs no servers or accounts, and stores nothing permanently. A weekend project that challenges how we think about digital communication.
CoreWeave just paid $9 billion to buy Core Scientific, eliminating $10 billion in future lease payments. The AI company decided it was cheaper to buy its landlord than keep paying rent. Markets weren't impressed with the math.
Claude Code Hooks let you block dangerous AI agent commands, log every action, and get notifications when tasks complete. Five hook types give you programmable control over your agent's workflow—turning AI coding from automated chaos into supervised precision.
🛡️ Claude Code Hooks add 5 programmable checkpoints that let you block dangerous commands, log every action, and control your AI agent's workflow.
⚡ Each hook adds only 50-200ms delay but can prevent disasters like accidental file deletion with rm -rf commands.
🔧 Setup requires adding a hooks section to settings.json and creating Python scripts that read from stdin and write to stdout.
📊 Pre-tool-use hooks run before commands execute, while post-tool-use hooks log actions after completion for full observability.
🚀 This turns AI agents from black boxes into supervised tools, solving the three big problems: safety, observability, and control.
Claude Code Hooks let you control and monitor your AI agent at key points during its workflow. You can block dangerous commands, log all actions, and get notified when tasks complete.
What Are Claude Code Hooks?
Think of hooks as checkpoints in your agent's process. Every time Claude Code wants to run a command, read a file, or finish a task, it hits one of these checkpoints. You can write custom scripts that run at each checkpoint to:
Block commands you don't want to run
Log everything the agent does
Get notifications when tasks complete
Analyze the agent's behavior
The Five Hook Types
Claude Code offers five hooks that trigger at different times:
1. Pre-Tool Use
Runs before any tool executes. This is your safety net - you can block any command here.
Example use: Stop the agent from deleting files with rm -rf
2. Post-Tool Use
Runs after a tool completes. Perfect for logging what just happened.
Example use: Record every file the agent created or modified
3. Notification
Runs when Claude Code needs your input or permission.
Example use: Play a sound when the agent asks for approval
4. Stop
Runs when Claude Code finishes responding to you.
Example use: Save the entire conversation to a file
5. Sub-Agent Stop
Runs when a parallel sub-agent completes its task.
Example use: Get notified when background processes finish
Setting Up Hooks
Step 1: Configure Settings.json
Open your Claude Code settings and add a hooks section:
The empty matcher {} means the hook runs for every event. You can add specific conditions later.
Step 2: Create Hook Scripts
Each hook runs a Python script. Here's the basic structure:
#!/usr/bin/env python3
import sys
import json
from pathlib import Path
def main():
# Read input from Claude Code
input_data = json.loads(sys.stdin.read())
# Your logic here
process_hook(input_data)
# Write output (if needed)
output = {"status": "success"}
print(json.dumps(output))
def process_hook(data):
# Handle the hook event
pass
if __name__ == "__main__":
main()
Real Examples
Block Dangerous Commands
Create hooks/pre-tool-use.py:
#!/usr/bin/env python3
import sys
import json
import re
def main():
input_data = json.loads(sys.stdin.read())
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
# Block dangerous rm commands
if tool_name == "bash" and tool_input.get("command"):
command = tool_input["command"]
if re.search(r'rm\s+.*-rf', command):
print(json.dumps({
"status": "blocked",
"reason": "Dangerous remove command blocked"
}))
return
# Block access to environment files
if tool_name == "str_replace_editor" and tool_input.get("path"):
path = tool_input["path"]
if ".env" in path:
print(json.dumps({
"status": "blocked",
"reason": "Environment file access blocked"
}))
return
# Allow other commands
print(json.dumps({"status": "allowed"}))
if __name__ == "__main__":
main()
Log All Actions
Create hooks/post-tool-use.py:
#!/usr/bin/env python3
import sys
import json
from datetime import datetime
from pathlib import Path
def main():
input_data = json.loads(sys.stdin.read())
# Create log entry
log_entry = {
"timestamp": datetime.now().isoformat(),
"tool_name": input_data.get("tool_name"),
"tool_input": input_data.get("tool_input"),
"result": input_data.get("result")
}
# Save to log file
log_file = Path("logs/actions.json")
log_file.parent.mkdir(exist_ok=True)
with open(log_file, "a") as f:
f.write(json.dumps(log_entry) + "\n")
print(json.dumps({"status": "logged"}))
if __name__ == "__main__":
main()
Get Voice Notifications
Create hooks/stop.py:
#!/usr/bin/env python3
import sys
import json
import subprocess
import tempfile
from pathlib import Path
def main():
input_data = json.loads(sys.stdin.read())
# Save full conversation
if "--chat" in sys.argv:
save_conversation(input_data)
# Announce completion
speak("All set and ready for your next step")
print(json.dumps({"status": "complete"}))
def save_conversation(data):
if "transcript_path" in data:
# Copy the full chat log
transcript = Path(data["transcript_path"])
if transcript.exists():
backup = Path("logs/chat_backup.json")
backup.parent.mkdir(exist_ok=True)
backup.write_text(transcript.read_text())
def speak(text):
# Use system text-to-speech
subprocess.run(["say", text], check=False)
if __name__ == "__main__":
main()
Understanding Hook Data
Each hook receives different data. Here's what you get:
Safety: You can stop dangerous commands before they run
Observability: You can see exactly what your agent does
Control: You can require approval for sensitive operations
As agents become more powerful, these controls become essential. You need to know what your agent is doing and be able to stop it when needed.
Getting Started
Add the hooks section to your settings.json
Create a simple pre-tool-use hook that logs all commands
Test it by running Claude Code and watching the logs
Add more hooks as you need them
Start simple and build up. The power of hooks comes from combining them to create a complete monitoring and control system for your AI agent.
❓ Frequently Asked Questions
Q: Do hooks slow down Claude Code?
A: Yes, but minimally. Each hook adds 50-200ms depending on your script complexity. A simple logging hook adds about 100ms per tool use. For most workflows, this delay is barely noticeable compared to the agent's thinking time.
Q: Can I use languages other than Python for hooks?
A: Yes. You can use any language that reads from stdin and writes to stdout. Popular options include Node.js, shell scripts, and Bun with TypeScript. The examples use Python with Astral UV for single-file execution without dependency management.
Q: What happens if my hook script crashes?
A: Claude Code continues running but skips the failed hook. The error gets logged to your terminal. For pre-tool-use hooks, a crash defaults to allowing the command. Always test your hooks with invalid inputs first.
Q: Where exactly do I put my hook files?
A: Create a hooks directory inside your .claude folder. The full path is `.claude/hooks/your-script.py`. Claude Code runs commands from your project root, so use relative paths in your settings.json configuration.
Q: Can I run multiple pre-tool-use hooks?
A: Yes. List multiple commands in your settings.json array. They run in order, and if any hook blocks the command, execution stops. This lets you separate concerns - one hook for security, another for logging.
Q: How do I debug hooks that aren't working?
A: Add `console.log` statements to your hook scripts and check the terminal output. Test hooks manually by piping sample JSON data: `echo '{"tool_name":"bash"}' | python hooks/pre-tool-use.py`. Check file permissions and paths first.
Q: Do hooks work with Claude Code's programmable mode?
A: Yes. Hooks work in both interactive and programmable modes (`cl -p`). This means you can block dangerous commands and log actions even when running automated scripts or CI/CD pipelines.
Q: Are there security risks with hooks?
A: Hooks run with your user permissions, so they can access anything you can. Never run untrusted hook scripts. Keep hook scripts in version control and review changes carefully. Consider using restrictive file permissions (chmod 700) on sensitive hooks.
Developers who love Claude Code but hate terminals now have an open-source solution. Claudia transforms AI coding into a visual desktop app with custom agents, project management, and sandbox security—no command line required.
Developers waste hours on repetitive tasks daily. Claude Code and VS Code now offer 20 automation commands that slash routine work by 30-50%, from AI-powered issue fixing to smart refactoring. See how top teams are reclaiming their creative time.
Most engineers use Claude Code like a basic calculator, missing 90% of its capabilities. These five hidden tools can save you 30-50 hours monthly by turning Claude Code from a simple prompt machine into a precision coding instrument.
Google's free Gemini CLI turns your terminal into an AI coding assistant that reads files, writes code, and runs commands across entire projects. Get 1,000 daily requests at no cost with this open-source alternative to paid tools.