Which of the default hooks can actually block a command (Chapter 3)
The default install writes eight hooks. Five run on PreToolUse, the moment before a tool
call; two on PostToolUse, after it; one on Stop. A hook that exits 2 on PreToolUse stops
the call and shows its message to the model.
Three of the eight carry a refusal. The other five cannot stop anything — they check syntax
after an edit, watch the context window, strip comments so an allowlist matches, auto-approve
read-only cd+git, and shout when a session dies on an API error. That ratio, three out of
eight, is this whole book in one install: the set you get by default is mostly witnesses, and
that is a reasonable design, but only if you know which is which.
These are the refusals, read out of the shipped scripts rather than from documentation.
Destructive commands (destructive-guard, PreToolUse on Bash). Nineteen distinct
refusals, among them:
1 BLOCKED: 'rm -rf *' removes everything in the current directory.
2 BLOCKED: --no-preserve-root detected.
3 BLOCKED: the deletion target is set in a variable in this same command.
4 BLOCKED: a destructive command is hidden inside a wrapper.
5 BLOCKED: git reset --hard discards all uncommitted changes.
Note the third and fourth: the guard is not only matching a literal rm -rf. It refuses when
the target is computed in the same command, and when the destructive call is wrapped, because
those are the shapes that walk past a naive pattern.
Pushes (branch-guard, PreToolUse on Bash). Two refusals:
1 BLOCKED: Force push detected.
2 BLOCKED: Attempted push to protected branch.
Read the force-push rule carefully, because it is stricter than most people expect: it matches
-f, --force and --force-with-lease. The safer form of a force push is refused too. The
script’s own comment says why — git push --force-with-lease (still destructive). The way
through is not a different flag but an explicit decision: set CC_ALLOW_FORCE_PUSH=1. Whether
you agree with that call or not, it is the one your machine is running, and it is the kind of
thing worth knowing before the moment you need it.
Credentials (secret-guard, PreToolUse on Bash). Four refusals:
1 BLOCKED: Attempted to stage .env file.
2 BLOCKED: Attempted to stage credential/key file.
3 BLOCKED: Attempted to stage a file matching CC_SECRET_PATTERNS.
4 BLOCKED: 'git add .' with .env file present.
The last is the useful one. Nobody types git add .env. They type git add . in a directory
that happens to contain one.
If you went looking in the repository and found different wording. There is a second, smaller set in
hooks/hooks.json— six hooks, allPreToolUse, with messages likeBLOCKED: recursive rm on non-safe target.That file is a starter manifest for people assembling their own configuration. Thenpxinstall does not use it; it writes the eight above, whose bodies live inscripts.json. If the message you see does not match the message you read, that is which file you are looking at — not a version skew.
What this list does not cover
A hook sees one tool call at a time. It does not see intent, and it does not see the second half of a plan. Anything that reaches the filesystem without going through a watched tool, such as a script that was written earlier and is now merely being executed, is outside the window. Read the list above as a floor, not a ceiling.
A related note from writing this book: while drafting Chapter 4, the credential guard on this author’s own machine blocked the command that was writing this manuscript, because the manuscript quotes a dangerous command inside a code block. That is a false positive, and it is the honest shape of this trade. A guard tight enough to catch the real thing will sometimes catch you writing about the real thing.