~/adventure-log/2025/07/claude-code-hooks-automation-guide
Tech

Automating Formatting and Linting with Claude Code Hooks

How to use Claude Code hooks to automatically run code formatting and linting commands (like mix format or prettier) whenever files are modified.

Published
Updated
Reading time
2 min
Tags
AIClaude Code

When working with Claude Code, running formatters (mix format, prettier, rubocop) and linters manually after every AI edit gets tedious quickly.

Claude Code includes a Hooks mechanism that runs specified shell commands automatically at key points in the workflow—such as immediately after a tool finishes editing a file.

Here is how to set them up and how I use them in my projects.

Configuration Scopes

Hooks are configured in Claude Code's settings JSON files. There are three levels of scope:

  • ~/.claude/settings.json — Global user settings (applied across all projects)
  • .claude/settings.json — Project settings (committed to git, shared with teammates)
  • .claude/settings.local.json — Local project overrides (gitignored, personal machine only)

Basic Setup: Format on File Edit

To run a formatter like mix format every time Claude Code modifies a file, configure a PostToolUse hook with a matcher for the Edit tool:

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "mix format"
          }
        ]
      }
    ]
  }
}

With this in .claude/settings.json, you no longer have to worry about unformatted code making it into your diffs.

Trigger Points and Matchers

Claude Code provides several trigger points:

  • PreToolUse: Runs before a tool executes. Useful for logging or validation.
  • PostToolUse: Runs after a tool completes successfully. Best for formatters and linters.
  • Stop: Runs when Claude finishes responding to the prompt.
  • Notification: Triggers when Claude sends a notification.

The matcher field controls which tool triggers the hook:

  • "matcher": "Edit": Triggers only on file edits.
  • "matcher": "Edit|Write": Regex matching multiple tools (e.g., both partial edits and whole file writes).
  • "matcher": "Bash": Triggers on command executions.
  • Omitted matcher: Runs on every event for that trigger point.

Multi-Command Example

You can chain multiple commands under a single trigger. For example, running both a formatter and a strict linter on every file modification, plus logging shell commands:

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "mix format"
          },
          {
            "type": "command",
            "command": "mix credo --strict"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"[$(date)] Running: $CLAUDE_TOOL_INPUT\" >> .claude/command_log.txt"
          }
        ]
      }
    ]
  }
}

Summary

Setting up a simple PostToolUse hook for your project's default formatter takes two minutes and removes the friction of manual cleanup after AI-assisted edits. If you work across multiple languages, putting language-agnostic preferences in user settings and project-specific linters in .claude/settings.json keeps things clean and predictable.

You got a collectible· Item get

No.010

Glimmer Crystal

Common

Region
The Mistlands
Found near
AI · Claude Code
Discovered
Journey
2 min · 1 traveller so far

Earned by finishing this quest. The more travellers who read it, the rarer it grows.

Epona
Written byEpona

There's nothing wrong with having a little fun

x.com/simura_epona

RelatedNearby quests

Loading comments…