Advanced

Hooks & Automation

Make things happen automatically when Claude acts.

What are hooks?

Hooks are commands that run automatically when Claude does something. They’re like rules: “Whenever Claude edits a file, also do this.”

Simple examples:

  • After Claude edits a document, automatically back it up
  • Before Claude deletes anything, log what’s being removed
  • When a session ends, save a summary

Hooks are configured in ~/.claude/settings.json.

When hooks run

HookWhen it runs
PreToolUseBefore Claude does something
PostToolUseAfter Claude does something
StopWhen Claude finishes responding
SessionEndWhen you end a session

You can make hooks run only for specific actions (editing, writing, running commands, etc.).

A simple example

Say you want to keep a log of every file Claude edits. You’d add this to your settings:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": { "tool_name": "Edit" },
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date): Edited $CLAUDE_FILE_PATH\" >> ~/.claude/edit-log.txt"
          }
        ]
      }
    ]
  }
}

Now every edit gets logged with a timestamp.

Practical uses

Backup before changes: Keep a copy before Claude modifies important files.

Notification when done: Play a sound or send a notification when a long task finishes.

Session summaries: When you end a session, automatically save what was discussed.

Keep it simple

Hooks run every time. If your hook is slow, it’ll slow down everything. Start with simple, fast actions.

For developers

Hooks become powerful for development workflows:

Auto-format on edit

{
  "matcher": { "tool_name": "Edit" },
  "hooks": [{
    "type": "command",
    "command": "prettier --write $CLAUDE_FILE_PATH"
  }]
}

Run tests after changes

{
  "matcher": { "tool_name": "Edit" },
  "hooks": [{
    "type": "command",
    "command": "npm test -- --findRelatedTests $CLAUDE_FILE_PATH"
  }]
}

Type-check TypeScript

{
  "matcher": { "tool_name": "Edit", "file_pattern": "*.ts" },
  "hooks": [{
    "type": "command",
    "command": "tsc --noEmit"
  }]
}

Hook input

Hooks receive JSON on stdin with context:

{
  "tool_name": "Edit",
  "file_path": "/path/to/file.ts",
  "session_id": "abc123"
}

LLM evaluation

Hooks can even use Claude to evaluate actions:

{
  "type": "prompt",
  "prompt": "Check if this edit introduces any security issues. Respond with {\"decision\": \"approve\"} or {\"decision\": \"block\", \"reason\": \"...\"}"
}

Toggle hooks on and off

For hooks you don’t always want running:

# Check for a file to enable/disable
if [ ! -f ~/.claude/hooks-enabled ]; then
  exit 0
fi
# ... rest of hook

Control with: touch ~/.claude/hooks-enabled or rm ~/.claude/hooks-enabled.


Official Documentation