π€ Hooks β Automating Your Workflow
Hooks let you set up automatic actions that run when Claude does something β like a spell check every time a file is saved, or a git commit after every task.
In this module
What are hooks?
dofile_linter to check for errors."
The hook runs in the background β you don't have to remember to do it.
It's like setting up an automatic alarm: configure it once, it triggers automatically.
Hooks are configured in Claude Code's settings file (settings.json) and run as shell commands in response to events in your session.
Types of hooks
| Hook type | Triggers when... | Research use case |
|---|---|---|
PreToolUse |
Claude is about to use a tool (read/edit/run) | Validate a file before Claude edits it; block risky operations |
PostToolUse |
Claude just used a tool successfully | Auto-commit after every file edit; run linter after saving code |
Stop |
Claude finishes a task (stops generating) | Send a notification; run tests; log what was done |
SubagentStop |
A sub-agent finishes | Aggregate results from parallel tasks |
Configuring hooks
Hooks are set in ~/.claude/settings.json (global) or .claude/settings.json (project-level). Here's the structure:
// ~/.claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "echo 'File saved: $CLAUDE_FILE_PATH'"
}
]
}
]
}
}
The matcher field specifies which tool triggers the hook (e.g., "Write", "Edit", "Bash"). You can also match on specific file patterns.
Research-specific hook examples
Auto-commit after every file edit
Never lose work by automatically committing every change Claude makes:
{
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "git add -A && git commit -m 'Claude: auto-save $(date +%H:%M:%S)' 2>/dev/null || true"
}]
}
]
}
Run Stata's dofile linter on save
{
"PostToolUse": [
{
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "if [[ '$CLAUDE_FILE_PATH' == *.do ]]; then echo 'Stata file saved: $CLAUDE_FILE_PATH'; fi"
}]
}
]
}
Desktop notification when Claude finishes a long task
{
"Stop": [
{
"hooks": [{
"type": "command",
"command": "osascript -e 'display notification \"Claude finished!\" with title \"Claude Code\"'"
}]
}
]
}
(Mac only β for Linux use notify-send, for Windows use PowerShell's New-BurntToastNotification)
Log all tasks to a research journal
{
"Stop": [
{
"hooks": [{
"type": "command",
"command": "echo \"$(date): Claude session ended\" >> ~/research-log.txt"
}]
}
]
}
Safety and caution
- A hook that deletes files or overwrites data will run every time the trigger fires
- Test hooks with
echocommands before using real operations - Never put sensitive information (API keys, passwords) in hook commands
- Start simple β one hook at a time, with logging so you can see what's happening
Module 7 Exercise: Set up your first hook
Set up a simple, safe hook that shows you what's happening:
- Open (or create)
~/.claude/settings.json - Add a
Stophook that logs "Claude finished at [time]" to a file called~/claude-activity.log - Start a Claude Code session, give it a small task, and verify the log file was updated when Claude stopped
- As a bonus: add a Mac/Linux desktop notification hook for long tasks
Hint: Ask Claude Code to help you write the settings.json syntax β "Add a Stop hook to my settings.json that logs each session end to ~/claude-activity.log"