Skip to content

Automating with Claude Code Hooks

Published:  at 02:22 PM
Table of Contents

What Are Claude Code Hooks?

Hooks are shell commands that execute automatically when certain events occur in Claude Code. They’re configured in your settings.json file and can trigger on events like:

Hook Configuration Structure

Hooks are defined in ~/.claude/settings.json (global) or .claude/settings.json (project-level):

{
  "hooks": {
    "EventName": [
      {
        "matcher": "optional-pattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-shell-command",
            "timeout": 5000
          }
        ]
      }
    ]
  }
}

Example 1: Audio Notifications

One simple but effective use of hooks is to get audio feedback when events occur. This is especially useful when Claude finishes a long-running task.

Configuration

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "afplay /System/Library/Sounds/Ping.aiff"
          }
        ]
      }
    ],
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "afplay /System/Library/Sounds/Ping.aiff"
          }
        ]
      }
    ]
  }
}

Or use text-to-speech:

{
  "type": "command",
  "command": "say 'Task completed'"
}

What This Does

Example 2: Auto-Syncing MCP Server Configuration

A more advanced use case is automatically backing up your MCP (Model Context Protocol) server configuration to your dotfiles repository.

Problem

Claude Code stores global MCP server configurations in ~/.claude.json, but this file also contains:

I want to version control MCP servers without tracking all this ephemeral state.

Solution

Use a SessionEnd hook to automatically extract and sync just the MCP configuration.

Files in This Configuration

Step 1: Create a Sync Script

Create ~/.dotfiles/scripts/sync-mcp-config.sh:

#!/bin/bash

# Sync MCP servers configuration from ~/.claude.json to dotfiles

SOURCE_FILE="$HOME/.claude.json"
DEST_FILE="$HOME/.dotfiles/claude/.claude/mcp-servers.json"

if [ ! -f "$SOURCE_FILE" ]; then
    echo "Error: $SOURCE_FILE not found"
    exit 1
fi

# Extract mcpServers section using jq
echo "Extracting mcpServers from $SOURCE_FILE..."
jq '{mcpServers: .mcpServers}' "$SOURCE_FILE" > "$DEST_FILE"

if [ $? -eq 0 ]; then
    echo "✓ MCP servers configuration synced successfully to $DEST_FILE"
else
    echo "✗ Failed to sync MCP configuration"
    exit 1
fi

Make it executable:

chmod +x ~/.dotfiles/scripts/sync-mcp-config.sh

Step 2: Add a Hook

Add this to your ~/.claude/settings.json:

{
  "hooks": {
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "$HOME/.dotfiles/scripts/sync-mcp-config.sh"
          }
        ]
      }
    ]
  }
}

What This Does

  1. Automatic Backup: Every time you exit Claude Code, your MCP configuration is automatically extracted and saved
  2. Clean Tracking: Only the MCP servers are tracked, not the entire state file
  3. Portable Setup: Easy to restore your MCP setup on new machines
  4. No Manual Work: You never have to remember to sync the configuration

Result

Your claude/.claude/mcp-servers.json will look like:

{
  "mcpServers": {
    "chrome-devtools": {
      "type": "stdio",
      "command": "npx",
      "args": ["chrome-devtools-mcp@latest"],
      "env": {}
    },
    "context7": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@upstash/context7-mcp@latest"],
      "env": {}
    }
  }
}

This file is clean, version-controlled, and automatically updated.

More Hook Ideas

Run Tests After Code Changes

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npm test",
            "timeout": 30000
          }
        ]
      }
    ]
  }
}

Format Code Automatically

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write $FILE"
          }
        ]
      }
    ]
  }
}

Log Session Activity

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date): Session started\" >> ~/.claude-sessions.log"
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date): Session ended\" >> ~/.claude-sessions.log"
          }
        ]
      }
    ]
  }
}

Send Desktop Notifications

# macOS
"command": "osascript -e 'display notification \"Claude has finished\" with title \"Claude Code\"'"

# Linux
"command": "notify-send 'Claude Code' 'Task completed'"

Resources