Guardrails for Claude Code

Intercept the
agent loop.

stdin→hook→exit 0 · pass  /  exit 2 · block

Small programs that watch what Claude Code is about to do, and step in. Block a destructive command. Refuse to read a secret. Stage and format an edit. Ping you on Slack. Twenty-two exhaustively tested plugins, each one command to install.

22Plugins
1949Tests pass
~35msPer call
0 · 2Exit codes
~/repo - claude
# Claude proposes an action… please clean up this directory tool Bash command rm -rf ~ PreToolUseblock-dangerous-commands ⊘ blockedexit 2 "rm -rf on home directory"
The contract

No SDK. Just a wire protocol.

plain executables
any language
the exit code decides
01 · in

Claude sends stdin

On every lifecycle event, Claude Code pipes a JSON payload (the tool, its input, the session) to your hook's standard input.

02 · decide

Your hook runs

A few hundred lines in Node, Python, or shell. Inspect the payload, check it against your rules, and choose a verdict.

03 · out

Return exit 0 or exit 2

0 lets the tool run. 2 blocks it and hands your message back to Claude as guidance.

Where they attach

Eight stops in the loop.

● covered here
○ tool execution
SessionStart
prepare context
UserPrompt
inspect / inject
PreToolUse
block or pass
· tool ·
execution
PostToolUse
react / log
Notification
alert you
Stop
finalize
SessionEnd
capture outcome
● covered by this repo: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Notification, Stop, SessionEnd ○ the middle stop is tool execution; SubagentStop, PreCompact, ConfigChange, and InstructionsLoaded are covered too
The catalog

The guardrail twelve.

Each installs with one command: /plugin install ↓

node + python
MIT licensed

01block-dangerous-commands

Refuses rm -rf ~, fork bombs, curl | sh, dd to a raw disk, and the long tail of catastrophes that look harmless in a one-liner. Three tunable safety levels decide where the line sits.

block-dangerous-commands
tool Bash command rm -rf ~ ⊘ blockedexit 2 "deletes home directory"

02protect-secrets

Stops Claude from reading, editing, or quietly exfiltrating .env files, SSH keys, AWS credentials, kubeconfig: anything load-bearing. Catches the obvious paths and the clever ones: a cat piped to curl is still exfiltration.

protect-secrets
tool Read path .env.production ⊘ blockedexit 2 "sensitive credential file"

03git-safety

Branch-aware guardrails: blocks commit, merge, rebase, reset and push while you're on main, plus destructive gh CLI calls like gh repo delete. Complements block-dangerous-commands rather than overlapping it.

git-safety
branch main command git push --force origin main ⊘ blockedexit 2 "force-push to a protected branch"

04auto-stage

After Claude edits or creates a file, runs git add on it, so git diff --cached becomes the canonical "what did the agent just do" view. One less accounting step in your loop.

auto-stage
# after Edit succeeds git add src/api.ts ✓ stagedexit 0 review → git diff --cached

05format-code

Runs the right formatter on whatever Claude just wrote: ruff for Python, prettier for JS/TS/HTML/JSON/Markdown/YAML. The agent's output lands already clean, so diffs stay about logic, not whitespace.

format-code
# after Write app.py ruff format app.py ✓ formattedexit 0 1 file reformatted

06notify-permission

Pings a Slack channel when Claude is stuck on a permission prompt or has gone idle waiting on you. Start a long agentic run, switch tabs, and trust you'll be pulled back when it actually needs a human.

notify-permission
event permission_prompt tool Bash (sudo) ↗ slack#claude-runs "Claude needs you in repo X"

07protect-tests

Stops the "fake green" ending: an agent that can't make a test pass will sometimes delete it, rename it out of discovery, or slip in a .skip. This hook refuses all three: while still allowing you to re-enable tests freely.

protect-tests
tool Edit file auth.test.js → describe.skip( ⊘ blockedexit 2 "tests must fail honestly"

08session-logger

Writes a durable markdown log of every session (repo, files touched, bash commands with secrets redacted): without adding a millisecond to the loop. Point CC_SESSION_LOG_DIR at an Obsidian vault and your agent keeps a diary.

session-logger
event SessionEnd repo ~/repo · 14 files · 31 cmds ✎ loggedsessions/2026-07-19.md "every session, remembered"

09case-insensitive-guard

On APFS, exFAT and NTFS, Content and content are the same path: an agent typing the wrong case deletes the real thing. Resolves every rm/mv target through cd chains and quotes, and blocks only provable case-collisions.

case-insensitive-guard
tool Bash command cd app && rm -rf Content ⊘ blockedexit 2 "'content' exists: same path on this disk"

10config-guard

Who guards the guards? Blocks the agent from rewriting its own guardrail config: settings.json, .claude/hooks/, .mcp.json, plugin manifests. Creating a protected file that doesn't exist yet counts as mutation (that exact gap was CVE-2026-25725). Reads always pass.

config-guard
tool Edit file .claude/settings.json ⊘ blockedexit 2 "guardrail config is protected"

11config-watch

The out-of-band sibling of config-guard: fires when any config file changes mid-session, whoever changed it. By default it makes the change loudly visible; CONFIG_WATCH_BLOCK=true refuses it outright. Written for the era of the CHAINDROP worm, which hid its payload in .claude/settings.json.

config-watch
event ConfigChange source user_settings ⚠ surfacedexit 0 "settings changed mid-session: verify it was you"

12instructions-audit

Scans every CLAUDE.md and rules file as it loads for hidden directives: invisible-Unicode smuggling, bidi overrides, secret exfiltration, decode-and-execute, hook tampering. The event can't block by itself, so the hook locks the session instead: every prompt and tool call is refused until a human fixes the file.

instructions-audit
event InstructionsLoaded file CLAUDE.md · zero-width run, line 41 ⊘ lockedexit 2 "hidden directive in a loaded rules file"

+ event-logger: a Python diagnostic that dumps every event's JSON so you can see an event's shape before you write a hook against it. The thing you reach for first.

The marketplace

Twenty-two plugins. One command each.

The guardrail twelve ↑ plus these eight workflow plugins, the subagent spawn cap, and the seven-in-one guard pack.

node · MIT
/plugin install
~/repo - claude
# 1 · add the marketplace, once /plugin marketplace add karanb192/claude-code-hooks # 2 · install any of the twenty-two by name /plugin install block-dangerous-commands@claude-code-hooks ✓ ready22 plugins available # or from your shell: claude plugin marketplace add · claude plugin install

13context-hogs

Per-file context-cost leaderboard: which files eat your tokens.

/context-hogs:leaderboard
PostToolUseSessionEnd

14cache-tax

The comeback price of a cold prompt cache, before you pay it: warns when your next message re-writes a lapsed 1-hour cache at up to 80x the read rate. Also a Mod form that refuses once and keeps the cache warm.

/cache-tax:status
UserPromptSubmitSessionStart

15nerf-receipts

Personal model-quality flight recorder: your own receipts when Claude feels nerfed.

/nerf-receipts:receipts
SessionStartPostToolUsePostToolUseFailureStopSubagentStopSessionEnd

16dead-rules-audit

CLAUDE.md compliance scorecard: which rules Claude actually ignores.

/dead-rules-audit:scorecard
SessionStartPostToolUseSessionEnd

17pr-provenance-stamp

Stamps a prompts / spend / tests / agent-authored receipt into PR bodies on gh pr create.

/pr-provenance-stamp:provenance
PreToolUsePostToolUse

18standup-autopilot

Writes your standup from what your agents actually did; re-injects yesterday's blockers.

/standup-autopilot:standup
SessionStartStopSessionEnd

19dead-end-registry

Remembers tried-and-reverted approaches; warns before you pay for a dead end twice.

/dead-end-registry:dead-ends
UserPromptSubmitPreToolUseStopSubagentStopPreCompact

20bounty-board

Prices TODO/FIXME debt as aging XP bounties; agents clear them as side quests.

/bounty-board:board
SessionStartPostToolUseSessionEnd

21guard-pack

All seven guards in one Node process: one ~35ms Node startup per tool call instead of seven.

/plugin install guard-pack@claude-code-hooks
PreToolUse

22subagent-spawn-cap

Per-session subagent spawn budget: asks at 20 and every 10 after, denies at 60, nested fan-outs included. The total cap Claude Code 2.1.224 dropped, back under your control.

/plugin install subagent-spawn-cap@claude-code-hooks
PreToolUse

Most recorders observe off the critical path: their PostToolUse and Stop hooks run async: true, so they write their receipts without adding latency to the agent loop. The exception is a hook whose output Claude reads back: bounty-board verifies and pays out its bounties synchronously.

The manual path

Copy. Register. Restart.

Every plugin installs with /plugin ↑. Prefer to own the file? Each hook is still a plain script you can copy.

~60 seconds
no build step
STEP i

Place the script

Anywhere your shell can chmod +x. Convention is ~/.claude/hooks/.

$ mkdir -p ~/.claude/hooks
$ cp plugins/block-dangerous-commands/block-dangerous-commands.js \
     ~/.claude/hooks/
STEP ii

Register it

In .claude/settings.json, bind the hook to an event and matcher.

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "node ~/.claude/hooks/block-dangerous-commands.js"
      }]
    }]
  }
}
STEP iii

Restart Claude Code

The hook is live. Ask Claude to do something reckless and watch it refuse.

$ claude
› please rm -rf ~
… hook blocked:
  deletes home directory.
Marginalia

Tradeoffs, in brief.

Safety

Three levels of paranoia

criticalcatastrophes only: rm -rf ~, fork bombs, dd
high+ risky: force push, secrets, hard reset★ default
strict+ cautionary: any force push, sudo rm
Runtime

Match language to event rate

Bashtiny guards10-20ms
Nodeper-tool, JSON-heavy35-115ms
Pythonsession events200-400ms
Exits

Two numbers do the work

0pass: let the tool run
2block: message goes back to Claude
·other: non-blocking warning, logged
Open

Forthcoming hooks.

contributions welcome
see CONTRIBUTING.md
20context-snapshot · preserve before compactionPreCompact
21ntfy-notify · free mobile pushNotification
22discord-notify · webhook alertsNotification
23tts-alerts · voice notifications via say/espeakNotification
24rules-injector · auto-attach CLAUDE.mdUserPromptSubmit
25rate-limiter · cap tool calls per minutePreToolUse

Put a hook in the loop.

Twenty-two tested plugins: twelve guardrails, a subagent spawn cap, eight workflow tools, and a seven-in-one guard pack, MIT licensed, no framework to learn. Install one and restart Claude Code, and you're protected in under a minute.