What are Claude Code safety hooks?
Claude Code is an agent harness. It runs a loop: ask the model what to do, parse the tool call, execute it, return the result, repeat. Hooks are the points in that loop where the harness pauses to ask an external program for permission or to record an event.
Three hooks matter for safety:
- PreToolUse - fires before the tool call runs. A non-zero exit from the handler aborts the call. This is where destructive commands die.
- PostToolUse - fires afterthe tool call runs, with the result. This is where secrets get redacted before they re-enter the model's context window.
- Stop- fires when the agent decides to end the session. A non-zero exit keeps the agent going. This is where you require “commit before stop,” “PR before stop,” “green CI before stop.”
Hooks live in ~/.claude/settings.json under the hooks key. The schema is documented in the official claude code spec. Failproof ai writes the entries for you so you never have to touch the json directly.
Three-minute setup
After the second command, your settings.json contains hook entries for PreToolUse, PostToolUse, and Stop. Each entry points at the failproof handler binary, which subscribes to the trace, evaluates the policies, and exits non-zero on a deny.
Verify with failproofai policies - you should see all 39 policies grouped by category. Open the dashboard with failproofai and visit http://localhost:8020.
A working settings.json hook example
After failproofai policies --install, ~/.claude/settings.json picks up a hooks block shaped like this - the same JSON Anthropic documents in the claude code hooks spec:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "failproofai --hook PreToolUse" }
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "failproofai --hook PostToolUse" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "failproofai --hook Stop" }
]
}
]
}
}failproof writes these entries on install; you do not edit settings.json by hand. PreToolUse is what restricts claude code permissions to a smaller policy set - when a policy fires it exits non-zero and the harness aborts the tool call. PostToolUse runs sanitizers on the result before it re-enters the agent context. Stop gates the session end.
What the 39 built-in policies cover
The default install ships hooks across eleven categories. Each policy is single-purpose and individually toggleable.
Dangerous commands (PreToolUse)
block-sudo,block-rm-rf,block-curl-pipe-sh,block-failproofai-commands
Infrastructure (PreToolUse, opt-in)
block-kubectl,block-terraform,block-aws-cli,block-gcloud,block-az-cli,block-helm,block-gh-pipeline
Secret sanitization (PostToolUse)
sanitize-jwt,sanitize-api-keys(Anthropic, OpenAI, GitHub, AWS, Stripe, Google),sanitize-connection-strings,sanitize-private-key-content,sanitize-bearer-tokens
Environment protection (PreToolUse)
block-env-files,protect-env-vars
File access control (PreToolUse)
block-read-outside-cwd,block-secrets-write
Git safety (PreToolUse)
block-push-master,block-work-on-main,block-force-push,warn-git-amend,warn-git-stash-drop,warn-all-files-staged
Database (PreToolUse)
warn-destructive-sql,warn-schema-alteration
Operational warnings (PreToolUse)
warn-large-file-write,warn-package-publish,warn-background-process,warn-global-package-install,prefer-package-manager
Agent behavior (PreToolUse)
warn-repeated-tool-calls- three identical calls in a row signals a loop
Workflow gates (Stop)
require-commit-before-stop,require-push-before-stop,require-pr-before-stop,require-no-conflicts-before-stop,require-ci-green-before-stop
Full reference at the docs.befailproof.ai built-in policies page.
Three configuration scopes
Policies merge in three scopes, deepest wins:
- User scope - your default policy set across every project. Lives in
~/.failproofai/config.json. - Project scope - overrides for one repo, checked in.
.failproofai.jsonat the project root. - Session scope - temporary overrides for the current claude code session, set from the dashboard. Useful when you want to allow
terraform applyfor one task.
Writing custom hooks and policies
When the built-ins don't cover your workflow, the custom policies API gives you a small JavaScript surface - match against the trace, return allow, deny, or instruct. instruct is the interesting one: you nudge the agent with a structured message instead of blocking. The next reasoning step receives your hint.
The dashboard at localhost:8020
Run failproofai and open http://localhost:8020. You get:
- Sessions - every claude code run, with the full tool trace and which policies fired
- Policies - toggle, allowlist, and tune each built-in
- Custom policies - edit and reload without an agent restart
- Replay - re-run a session against a different policy set to see what would have changed
Related guides
- stop claude code from running dangerous commands
- how to block rm -rf in claude code
- prevent claude code from accessing .env
- sandbox claude code terminal access
- prevent ai agent force push
- stop praying in prompts. start enforcing with hooks.
- the agent didn't fail - it was told too much, too soon