Hooks run shell commands at fixed points in a session — after a file is written, before a tool runs, when a turn ends. They are the one part of a configuration that executes code without being asked each time, which makes the quiet failures worth catching. A matcher naming a tool that does not exist never fires and never complains. A command reaching for an argument gets an empty string, because the event arrives on standard input as JSON rather than as arguments. And only some events can actually stop what was about to happen. This builder covers all three, and says which events can block and which are only observers.
Features
Every event listed with what it fires on
Matchers checked against real tool names, with case-sensitivity caught
Warns when a matcher is set on an event that has no tool
Warns when a command reaches for arguments it will never receive
Says which events can block an action, and how
Common matcher patterns offered as one-click presets
Several hooks grouped correctly by event and matcher
Flags a destructive command before it runs unattended
How to use the Hooks Builder
Pick the event you want to fire on
Add a matcher if the event is tool-specific
Write the command, reading the payload from standard input
Read the warnings, then merge the output into settings.json
Example
Input
prettier --write "$1"
Output
Warning: $1 will be empty — a hook is not given arguments
The event is piped in as JSON; read it with jq.
Common errors & troubleshooting
The hook never runs. — Usually the matcher. Tool names are capitalised and case-sensitive — Write, not write — and a name that does not exist matches nothing, silently.
The command runs but gets no input. — Hook input arrives on standard input as JSON. Read it with something like jq -r '.tool_input.file_path' rather than expecting an argument.
My hook cannot stop the tool call. — Only some events can, and only by exiting with status 2. Anything else is treated as “carry on”, and events like PostToolUse fire after the fact regardless.
The session hangs on my hook. — Set a timeout. A hook that waits on something — a network call, a lock — holds the whole session while it does.
Frequently asked questions
Which event should I use for a formatter?
PostToolUse with a matcher for the writing tools, so it runs after the file exists. Formatting before the write has nothing to format.
How does a hook receive the event?
As JSON on standard input — the tool name, its input, and the context around it. Nothing is passed as command-line arguments, which is why a command written around $1 silently receives nothing.
Can a hook stop a tool from running?
Before the tool runs, yes: exiting with status 2 blocks it. Which events allow that is shown as you pick one, because trying to block from an event that fires afterwards is a common and confusing mistake.
Do hooks run without asking?
Yes — that is the point of them, and the reason to read one carefully before adding it. A hook that deletes files is flagged here, but the general rule is that anything in this file runs unattended.
Can I have several hooks on one event?
Yes. Hooks sharing an event and a matcher are grouped together in the output, which is the shape the settings file expects.
Related tools
Permission Rule Tester — Test allow, ask and deny rules against real commands before you trust them.
Slash Command Builder — Build a custom slash command, with arguments and a tool allow-list.
Subagent Builder — Build a subagent definition file with its tools and model set.