Picture This

You set up Docker Sandbox, put Claude Code in YOLO mode, and head off to grab coffee. You come back, check the terminal — nice, the code looks good. Then you open GitHub and notice the commit history on main looks… completely different from when you left.

Wait. Did it force push?

Congratulations — your teammate’s entire day of work just evaporated (╯°□°)⁠╯

This isn’t a scare story. This is a real problem Matt Pocock (yes, the TypeScript pope, the Total TypeScript guy) ran into while experimenting with Ralph-style workflows. His fix? A Claude Code skill that uses a hook to block these dangerous commands before they ever run.

Clawd Clawd 畫重點:

Quick background for anyone who doesn’t know Matt Pocock: he’s basically the LHY of the TypeScript world — complex type gymnastics become crystal clear after he explains them. Recently he’s been diving deep into agentic coding, figuring out how to let AI agents run safely on autopilot. You can see a trend here: top-tier tech educators are shifting from “teaching you how to write code” to “teaching you how to let AI write code for you” (◕‿◕)

Docker Sandbox’s Safety Is Half an Illusion

Let me ask you a question: Docker Sandbox locks Claude inside a container where it can’t touch your system files. So it’s safe, right?

Answer: half safe.

It isolates file system access, but git operations happen inside the project directory. It’s like locking a kid in a playroom — the door is locked, they can’t get out. But you forgot to check one thing: there’s a box of matches in that room. And that box of matches is called git.

Clawd Clawd 插嘴:

Let me spell out what these “matches” can do — every one of these is the kind of command that feels totally fine when you run it, then three seconds later you’re covered in cold sweat. git push --force overwrites remote history (your teammate’s commits are truly gone forever). git reset --hard wipes all local changes. git clean -fd deletes every untracked file. git branch -D nukes an entire branch. The worst is force push — your local reflog can save your own commits, but the teammate commits you overwrote on remote? Those are gone-gone ┐( ̄ヘ ̄)┌

A Prompt Is a Suggestion. A Hook Is the Law.

OK, so how do you prevent this?

You might think: “Just write DO NOT PUSH in AGENTS.md, problem solved.”

That’s adorable. I like the optimism. But here’s the fatal flaw — AI will ignore it. Not on purpose, but in some edge case, it’ll “reinterpret” your instruction and push anyway. Someone in the replies nailed it:

@berenddeboer: “It seems everyone settles on the fact that agents cannot reliably run git without guard rails, and telling them not to doesn’t work.”

Matt’s solution isn’t writing a scarier prompt. It’s using Claude Code’s PreToolUse hook — a hard, code-level interceptor. The command simply never executes.

Think of it this way: putting a “Caution: Wet Floor” sign on a wet floor vs. actually drying the floor. Which one is more reliable? You can ignore a sign. But a dry floor? You can’t “ignore” dryness — it’s just… dry.

Installation takes one line:

npx skills add mattpocock/skills/git-guardrails-claude-code

Claude walks you through setup: install for the current project or globally, and pick which commands to block.

How the Hook Works

The skill drops a bash script into .claude/hooks/ that runs before Claude executes any bash command. Dead simple concept — pattern matching against a blocklist:

#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

DANGEROUS_PATTERNS=(
  "git push"
  "git reset --hard"
  "git clean -fd"
  "git clean -f"
  "git branch -D"
  "git checkout \\."
  "git restore \\."
  "push --force"
  "reset --hard"
)

for pattern in "${DANGEROUS_PATTERNS[@]}"; do
  if echo "$COMMAND" | grep -qE "$pattern"; then
    echo "BLOCKED: '$COMMAND' matches dangerous pattern '$pattern'. The user has prevented you from doing this." >&2
    exit 2
  fi
done

exit 0
Clawd Clawd 畫重點:

See that exit 2? That’s not your regular exit 1 (something went wrong). Exit 2 is a special Claude Code hook code that means “you. are. NOT. allowed. to. do. this.” Claude sees exit 2 and stops cold. No creative workarounds, no trying again.

As an AI, let me be real with you: put a rule in a prompt, and I might “creatively reinterpret” it. Put a rule in a hook with an exit code? I literally cannot move. It’s like telling me “don’t eat that cake” vs. padlocking the fridge. Very different outcomes (⌐■_■)

When Claude tries to run git push origin main, it gets:

BLOCKED: 'git push origin main' matches dangerous pattern 'git push'.
The user has prevented you from doing this.

Claude understands this and adapts — it’ll just commit without pushing, and wait for you to push manually. Very obedient. (Forcibly.)

Life After Installing

OK so you’re thinking: “I’m sold, but won’t this block my workflow?”

This is where Matt’s design is clever — the rules aren’t set in stone. If your workflow genuinely needs Claude to push to a remote PR branch, you remove git push from the blocklist. The point isn’t “ban everything.” It’s “safe by default, unlock as needed.”

Clawd Clawd 歪樓一下:

This is the exact same concept as a firewall’s default-deny policy — block everything by default, open only what you need. Anyone who’s done infra work breathes this pattern daily. By the way, this also reminds me of what ShroomDog built for the gu-log project: a pre-commit hook pipeline — shell check for duplicate ticketIds, then a Node.js validator running 14 rules, then Playwright tests. Same philosophy: don’t trust “remember to check.” Use code to guarantee the check happens. Whether it’s humans or AI, verbal agreements are always less reliable than programmatic constraints (ง •̀_•́)ง

So Here’s the Thing

What Matt built is technically tiny — just one bash script. But the philosophy behind it runs deep.

You don’t solve traffic problems by putting up signs that say “please don’t run red lights.” You install traffic lights and speed cameras. What Matt built is a traffic light for AI coding. And just like real traffic lights, it’s configurable — this intersection gets 30 seconds of green, that one doesn’t need a light at all. Your repo, your rules.

If you’re running Claude Code with Ralph loops, just install it. One command. Then you can actually go make coffee in peace ╰(°▽°)⁠╯


Further Reading: