Claude Code hooks, and using them to govern every tool call
Claude Code hooks are commands that Claude Code runs at fixed points in a session, such as before a tool call, after one, or when a prompt is submitted. A hook sees what is about to happen and can change the outcome, which makes it the one place a rule can stand in front of the agent without the agent having to cooperate.
This page covers the hooks that matter for keeping an agent safe, how a
PreToolUse hook decides a call, and what it takes to turn that into rules that
hold. The last part is what Memnox installs for you.
The hook events that matter for safety
Claude Code has many hook events. Four of them decide what an agent does:
| Event | When it fires | What it is good for |
|---|---|---|
SessionStart | a session begins or resumes | telling the agent the rules before it plans |
UserPromptSubmit | you submit a prompt, before Claude reads it | adding what the team already decided about the subject |
PreToolUse | before a tool call runs | allowing, asking about or denying the call |
PostToolUse | after a tool call succeeds | checking what a command actually changed |
How a hook is configured
Hooks live in settings.json under the event name, with an optional matcher
that picks which tools the hook applies to:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "./check-command.sh" }]
}
]
}
}The command receives the tool call as JSON on its standard input.
How a PreToolUse hook allows, asks or denies
A PreToolUse hook decides a call in one of two ways.
- Exit code 2 always blocks the call, and whatever the hook printed to standard error is shown to Claude as the reason.
- Exit code 0 with JSON decides through
hookSpecificOutput, withpermissionDecisionset toallow,askordeny, and apermissionDecisionReasonthat Claude sees on a deny and you see on an ask.
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "main is shared. Push a branch and open a PR."
}
}A deny from a hook still blocks the call in bypassPermissions mode, which is
what --dangerously-skip-permissions starts. Skipping the prompts does not skip
the hooks, and that is why a hook is the right place for a rule you never want
switched off.
Why a hand-written hook stops short
One script is easy to write. Keeping it right is the hard part.
- It only covers Claude Code. Codex, Cursor, Gemini CLI and Windsurf each have their own hook format, and a rule in one does nothing in the others.
- A shell command has to be parsed.
git push --force origin mainandgit push origin featureare bothBash, so the script has to understand every command it cares about, including one hidden insidesh -c. - A deny with no way forward stalls the agent. The reason has to say what to do instead, or the agent retries or gives up.
- Nobody sees what it decided. A script that exits 2 leaves no record of why, or of how often.
Memnox is those hooks, written once
memnox setup installs the hooks for you, in every agent it finds, and they all
read one rule file:
npm install -g memnox
memnox setupIn Claude Code it wires the four events above:
SessionStarttells the agent where it stands: the mode, what is never run here, what asks first, and the project boundary.UserPromptSubmitadds a decision your team already took when a prompt touches it, with who confirmed it and where.PreToolUseanswers every tool call with allow, ask or deny, from rules matched against the action rather than a model's judgement. A deny names what to use instead, so the agent finishes the task.PostToolUsereads what a shell command actually wrote, so an edit made throughsed -iis held to the same checks as one made with the edit tool.
The same rules reach Codex, Cursor, Gemini CLI and Windsurf through their own
hooks, and every verdict is recorded, so memnox why can say why a call was
refused. Memnox in your session shows exactly what
the agent is told, and Coding agent permissions
compares this with each agent's own permission modes.
Questions people ask
What is a PreToolUse hook in Claude Code?
A command Claude Code runs before every tool call it matches. It can let the
call run, ask you about it, or block it with a reason, through its exit code or
a JSON permissionDecision.
Do hooks run with --dangerously-skip-permissions?
Yes. Skipping permissions removes the prompts, not the hooks, and a deny from a
PreToolUse hook still blocks the call in bypassPermissions mode.
Can a hook ask me instead of blocking?
Yes. Return permissionDecision set to ask, and Claude Code shows its own
permission prompt with the hook's reason in it.
Do Cursor, Codex and Gemini CLI have hooks too?
Each has its own hook system in its own format. Memnox installs a hook in each of them from one rule file, so the same call gets the same verdict whichever agent makes it.

