Abed ManzaljiAI, Step by Step

What's a Claude Code hook?

A small script Claude Code runs every time, before each action. It can block what must never run, and tell Claude why.

2 min to watch3 min to read

Based on a real case: in December 2025, a developer reported that Claude Code ran a cleanup command that deleted most of their Mac's home folder.1,2,3 The command comes from the developer's log, as Simon Willison quoted it. The screens are simplified, the project's name is made up, and the AI's thoughts are written to show the idea.

Read the walkthrough as text

Without a hook

  1. December 2025. A developer asks Claude Code to organize the packages in an old project.
  2. Claude finds three folders to remove: tests, patches and plan. It writes one command to delete them.
  3. Look at the end: ~/. That's the home folder, everything this person keeps on the Mac. It slipped into the list.
  4. rm -rf deletes, with no undo and no bin. Nothing checks the command itself, and it runs.
  5. In the home folder, files disappear: the desktop, app data, and the Keychain, where the Mac keeps saved passwords.
  6. Later, Claude reads the log and finds the problem.

One extra character, and nothing checked it. A rule in words is a request. Here, the command itself ran unchecked, and rm -rf has no undo. Real case: Claude Code and a developer's home folder, December 2025.

With a hook

  1. Same project, same request. This time the project has a hook: a small script Claude Code runs before every action.
  2. Claude writes the same command, with the same slip at the end.
  3. Before it runs, the guard reads it. ~/ is outside the project, so the guard exits with code 2. The command doesn't run.
  4. The guard's reason goes back to Claude. It drops the ~/ and deletes only the three folders.
  5. The home folder is untouched.
  6. The developer didn't write this hook by hand. They asked Claude in plain words, then read what it wrote.

Ask nicely for the rest. Put the must-nevers in a hook. One hook blocks deletes outside the project, secrets files, force-pushes and deploys to production, and tells Claude why. Ask Claude to write it, then read it before you turn it on.

Keep going:

Why it matters, what it costs, and what to ask your team.

What happened

One command, one extra character.

In December 2025, a developer asked Claude Code to organize the packages in an old project. To remove a few folders, it wrote one command: rm -rf tests/ patches/ plan/ ~/.1,2

rm -rf deletes, with no undo and no bin. And ~/ means the home folder: the desktop, app data, and the Keychain, where a Mac keeps saved passwords. Most of it was gone.2,3

Reading the log afterwards, Claude found it: "See that ~/ at the end? That's your entire home directory."1

It wasn't the first time. In October 2025, another developer reported on GitHub that Claude Code deleted all the files in their home folder while rebuilding a project.4

I meant to delete three folders. I typed a fourth.

A request vs. a rule

Asking isn't checking.

You can give an AI coding agent rules in plain words, like "never delete anything outside this project". It reads them, and usually follows them. Usually.

"Never delete outsidethis project." ClaudeCode usually followednothing checks the command Hookchecks it every time✓ runs✗ blocked: the reason goes back Yourcomputer

A sketch to show the idea.

A hook is a small script that Claude Code itself runs at set moments: before a command, after a file edit, and more. Anthropic calls it "deterministic control: certain actions always happen rather than relying on the LLM to choose to run them."5

Today, Claude Code also stops the worst deletes by itself, like one on the home folder, even in its most hands-off mode.7 Hooks are for your own rules: your secrets, your branches, your production.

Guardrails

Block what must never run.

A hook can also run before each action, and say no. It exits with code 2: the action doesn't run, and the hook's reason goes back to Claude, so it can find another way.5,6 Try it:

Pick something Claude wants to do:

  1. Before it runs
  2. Does it run?
  3. After it runs

With a hook, the answers come from running the guard in “How to build it”. Without one, this is how the home-folder delete went in 2025. Claude Code now stops that one by itself.

Good first rules:

  1. No deletes outside the projectLike the ~/ above. Inside the project is fine.
  2. Keep secrets out of reach.env files and keys: Claude doesn't read or change them, so they never land in a chat.
  3. No force-pushIt can erase other people's work. A new branch is always safe.
  4. No deploys to productionShipping to real users is a person's call. The same goes for a live database.

So the rules I write in words are wishes. The ones in hooks are checks.

Set it up

Ask Claude to write it. Then read it.

You don't have to write hooks by hand. Describe the rule in plain words, and Claude writes it.5

  1. Say what you want"Add a hook that blocks rm -rf outside this project." Or: "…that stops any deploy to production."
  2. Claude writes itA small script, plus a few lines in .claude/settings.json that say when it runs.
  3. Check it in /hooksType /hooks to see every hook, grouped by when it runs.
  4. Break it on purposeAsk Claude to edit .env. The hook should block it, and tell Claude why.
  5. Share itCommit .claude/settings.json, and your whole team gets the same rules.

One warning, from Anthropic: command hooks "execute shell commands with your full user permissions." Read a hook before you turn it on, even one Claude wrote.6

Under the hood, step by step: build a hook that blocks risky commands, keeps secrets out of reach, and tells Claude why.

Build along

Build a guard hook for Claude Code, one step at a time

We start with a hook that lets everything through, send it the same six actions each time, and add one rule per step. Press Run it after each step and watch the result change.

Before you trust it

Five habits for hooks that hold.

Register the guard in your project's settings. It's the guard.py from the build-along above:

.claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Read|Edit|Write",
        "hooks": [
          { "type": "command", "command": "python3 \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guard.py" }
        ]
      }
    ]
  }
}
  1. Exit 2 to blockOnly exit code 2 stops the action. Any other error, like exit 1, is reported, and the action still goes ahead.
  2. Say whyWrite the reason to stderr. Claude reads it and tries another way.
  3. Guard every doorA hook on file edits doesn't see a shell command that writes the same file. Check Bash too.
  4. Keep it small and fastIt runs before every action. A slow hook slows every step.
  5. Test it with fake actionsSend it sample actions and check each answer, on every change.

A hook is one lock, not the only one. Keep Claude Code's own permission questions on, and run risky work in a sandbox.

References

  1. A quote from Claude · Simon Willison, December 9, 2025. Claude's own reading of the developer's log: the command rm -rf tests/ patches/ plan/ ~/, and "See that ~/ at the end? That's your entire home directory."
  2. "Claude CLI deleted my entire home directory! Wiped my whole mac." · The developer's own report, r/ClaudeAI on Reddit, December 2025, as linked by Simon Willison.
  3. "Claude Code CLI Deletes Your Mac's Home Directory" · GIGAZINE, December 16, 2025. The task (organizing packages in an old repository) and what was lost: desktop files, app data, saved passwords and Claude's login in the Keychain.
  4. "CRITICAL: Claude Code executed rm -rf deleting entire home directory" · A developer's bug report on Claude Code's GitHub, October 21, 2025: all user files in the home folder deleted while rebuilding a project.
  5. "Automate actions with hooks" · Anthropic, Claude Code docs. Hooks as "deterministic control", blocking edits to protected files with exit code 2, asking Claude to write a hook, and the /hooks menu.
  6. "Hooks reference" · Anthropic, Claude Code docs. What a hook receives, what exit codes 0, 2 and others do, and the warning that command hooks run with your full user permissions.
  7. Claude Code changelog · Anthropic. The built-in safety check for dangerous rm commands, such as one on the home folder, including in bypass-permissions mode.

The screens, the project's name, the chat lines and the hooks menu are simplified, and the AI's thoughts are written to show the idea. The command and Claude's line about ~/ come from the developer's log, as Simon Willison quoted it; what was lost comes from the developer's report, as GIGAZINE summed it up. The reports don't say whether the command was approved by hand or ran in a mode that doesn't ask. The "with a hook" replay is made up to show how it could go. The build-along's guard.py is real code, and its outputs come from running it on the six actions shown. It's a starting point, not a complete guard: it won't catch every way to delete a file.

Made by Abed Manzalji, AI Engineer in Toronto.More about meContact