Normies Guide

Module 7 of 10

Module 710 min read

Hooks — Automation That Runs Itself

set up automated actions that trigger before, during, and after Claude Code sessions. After this module, your setup will back itself up automatically, catch dangerous operations before they happen, and validate your work as you go.

What Hooks Do

Every module so far has been about things you actively do — write a CLAUDE.md, create a skill, run a command. Hooks are different. Hooks are things that happen without you doing anything.

A hook is a small script that runs automatically when something specific happens in Claude Code. "When a session starts, do this." "Before Claude runs a terminal command, check this." "When a session ends, do that."

You set them up once. They run forever after. You don't invoke them, you don't think about them, you don't even notice them — until the day they save you from a mistake.

Hooks cost zero tokens. They run as shell scripts, not Claude messages. You're getting automation for free.

Here's how the hook system works:

How hooks execute
  Event triggers                   Your hook scripts
  ─────────────                   ─────────────────

  ┌──────────────┐  matcher  ┌──────────────────────┐
  │ SessionStart │── "" ────▶│ git-sync.sh          │
  └──────────────┘  (all)     backs up ~/.claude/
                             └──────────────────────┘

  ┌──────────────┐  matcher  ┌──────────────────────┐
  │ PreToolUse   │── Bash ──▶│ safety-gate.sh       │
   (before cmd)            blocks rm -rf, etc.
  └──────────────┘           └──────────────────────┘

  ┌──────────────┐  matcher  ┌──────────────────────┐
  │ PostToolUse  │── Write ─▶│ lint-check.sh        │
   (after edit)            validates your code
  └──────────────┘           └──────────────────────┘

  ┌──────────────┐  matcher  ┌──────────────────────┐
  │ SessionEnd   │── "" ────▶│ git-sync.sh          │
  └──────────────┘  (all)     saves your changes
                             └──────────────────────┘

  cost: 0 tokens — hooks run as shell scripts, not Claude messages
Hooks fire automatically at specific events. You set them up once — they run forever.

How Hooks Work (The Mental Model)

Before we set anything up, let's understand the system. Claude Code has four hook points — moments where it pauses and runs your scripts:

Hook PointWhen It FiresUse Case
SessionStartWhen you launch Claude CodeSetup, sync, loading context
SessionEndWhen you close a sessionBackup, cleanup, logging
PreToolUseBefore Claude takes an actionSafety checks, validation
PostToolUseAfter Claude completes an actionVerification, quality checks

These are the four most commonly used hook points. Claude Code has 20+ hook points for advanced use cases — but these four cover everything a beginner needs.

The matcher field lets you filter which actions trigger the hook. "Bash" means only terminal commands. "Edit|Write" means only file modifications. You can be as specific or broad as you need.

Each hook script receives context about what's happening (the command being run, the file being edited) and can either allow it, block it, or add information to the conversation. Claude Code supports other types of hooks for advanced use cases, but command hooks (small automation scripts) are the simplest and what we'll use here.

·

The Three Hooks That Matter

There are many things you could automate with hooks. We're going to set up three. These three handle the most common failure modes: losing your work, running something dangerous, and shipping broken code.

Hook 1: Auto-Backup (git-sync)

What it does: Every time you start or end a Claude Code session, this hook automatically saves your .claude/ configuration to a backup. Your CLAUDE.md, skills, commands, settings — everything you've built in this guide gets backed up automatically.

Why it matters: You've spent real time building this setup. Without a backup, one bad edit to your CLAUDE.md or an accidental file deletion means starting over. This hook means you never lose your configuration.

How it works:

The setup prompt configures all of this automatically. Here's what it does under the hood, so you understand the pieces.

First, it initialises git (a version control tool that tracks changes) in your .claude/ directory. This lets the hook save snapshots of your configuration over time.

It creates a .gitignore file so temporary files and caches don't get backed up. This matters more than you'd expect — without it, your backup repository can balloon to several gigabytes from conversation history and cached data alone:

code
# Claude Code runtime data (ephemeral, regenerated each session)
debug/
cache/
file-history/
paste-cache/
shell-snapshots/
telemetry/
statsig/
usage-data/
session-env/
chrome/

# Conversation history (can grow to gigabytes)
history.jsonl

# Ephemeral task/plan/team data
plans/
tasks/
teams/
todos/

# Downloaded plugins (re-downloadable from marketplace)
plugins/marketplaces/
plugins/cache/

# Project transcripts (keeps memory files, ignores multi-GB session logs)
projects/**/*.jsonl

# Backups of backups
backups/

# OS files
.DS_Store

Then it creates the hook script itself at ~/.claude/scripts/hooks/git-sync.sh:

bash
#!/bin/bash
cd ~/.claude

# Only sync if there are actual changes
if [ -n "$(git status --porcelain)" ]; then
    git add -A
    git commit -m "Auto-sync: $(date '+%Y-%m-%d %H:%M')" --quiet
fi

Finally, it registers the hook in ~/.claude/settings.json so Claude Code knows when to run it:

json
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/scripts/hooks/git-sync.sh",
            "timeout": 30
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/scripts/hooks/git-sync.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

The "matcher": "" means "matches all session types" (SessionStart can filter by source like startup or resume, but an empty matcher runs on all of them). The "type": "command" tells Claude Code this is a shell command to execute.

That's it. From now on, every time you start or end a Claude Code session, your configuration is automatically backed up. You'll never think about it, and you'll never lose your setup.

Optional but recommended: If you have a GitHub account, the setup prompt can also connect these backups to a private GitHub repository for offsite storage. When enabled, the hook script adds a push step:

bash
#!/bin/bash
cd ~/.claude

if [ -n "$(git status --porcelain)" ]; then
    git add -A
    git commit -m "Auto-sync: $(date '+%Y-%m-%d %H:%M')" --quiet
    git push --quiet 2>/dev/null &
fi

The & at the end means the push happens in the background — it doesn't slow down your session start.

·

Hook 2: Safety Gate

What it does: Before Claude Code runs any terminal command, this hook checks whether the command is potentially destructive. If it is, the hook blocks it and warns you.

What it catches:

The hook blocks commands that are almost never what you want:

  • rm -rf on system directories (home folder, root, system paths)
  • Disk formatting commands (mkfs, dd)
  • Fork bombs and resource exhaustion
  • Commands that exfiltrate credentials or sensitive files

It deliberately doesn't block things that are sometimes dangerous but often legitimate — like force-pushing to git or running destructive database queries. Those require judgement, not blanket blocking. Claude's own safety checks handle those.

The script:

The setup prompt creates this at ~/.claude/scripts/hooks/safety-gate.sh. Here's what's inside:

bash
#!/bin/bash

# Read the command Claude wants to run from the hook input
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | grep -o '"command":"[^"]*"' | sed 's/"command":"//;s/"$//')

# Block catastrophic operations
BLOCKED_PATTERNS=(
    "rm -rf /"
    "rm -rf ~"
    "rm -rf \$HOME"
    "mkfs"
    "dd if="
    ":(){ :|:& };:"
)

for pattern in "${BLOCKED_PATTERNS[@]}"; do
    if echo "$COMMAND" | grep -q "$pattern"; then
        echo "Blocked by safety gate: potentially destructive operation" >&2
        exit 2
    fi
done

exit 0

The setup prompt makes this executable and registers it in settings.json alongside the other hooks:

json
"PreToolUse": [
  {
    "matcher": "Bash",
    "hooks": [
      {
        "type": "command",
        "command": "bash ~/.claude/scripts/hooks/safety-gate.sh",
        "timeout": 5
      }
    ]
  }
]

The "matcher": "Bash" means this hook only runs when Claude is about to execute a terminal command — not when it reads files or edits text.

Token cost: Zero. Hooks run outside of the Claude conversation. They don't consume any of your tokens.

·
·
·

What We Didn't Automate (And Why)

Hooks can do a lot more than what we've set up. You could automate testing, quality checks, deployment, notifications — anything an automation script can do. But each hook adds complexity and potential failure points.

We chose three hooks because they cover the three highest-impact automation needs:

  1. Don't lose your work (git-sync)
  2. Don't break your computer (safety-gate)
  3. Don't ship broken code (tsc-check)
Over-automated setup

12 hooks running on every action. Session startup takes 5 seconds. A hook fails silently and you don't notice for a week. Debugging hooks takes longer than the tasks they automate.

Our approach: three hooks

Backup (don't lose work), safety gate (don't break things), type check (don't ship broken code). Everything else is optional complexity you add when you feel the need.

Everything else is optional. If you find yourself manually doing something at the start or end of every session, that's a candidate for a hook. But start with these three and add more only when you feel a specific need.

·

Your setup now runs on autopilot in the background. Configuration is backed up automatically. Dangerous commands are caught before they run. Code quality is checked as you work. None of this costs tokens. None of it requires your attention. It just works.

Next: the memory system. Making Claude remember things across sessions — not just preferences, but actual knowledge about you and your work.