Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Hook Model

Claude Code exposes many hook points; tool-gates registers on the four that gate tool calls. Each one closes a gap the others can't. Codex CLI and Antigravity CLI expose fewer of them; the engine routes around what's missing. Gemini CLI remains available as a deprecated compatibility path for existing setups; Google's consumer CLI sunset date was 2026-06-18.

This page shows when each hook runs. Mode-specific policy lives one layer up in Permission Modes.

tool-call lifecycle · Claude Code
Tool call
Bash · Monitor · Write · Edit · MCP · Skill. The assistant emits a tool-use event.
PreToolUse
Decide
Shell parsed with tree-sitter and routed to the right gate. Returns allow, ask, or deny. Modern-CLI hints, file guards, and Tier 1 source-file secret denies ride here. Deny recovery is rendered into additionalContext; confirmed source-file recovery names Claude's Read tool.
PermissionRequest
fires for subagents
Re-decide
Subagents ignore PreToolUse's allow. This hook re-runs the gate so the same policy applies to delegated work.
PermissionDenied
fires when the auto-mode classifier denies
Retry hint
If the classifier denied a call tool-gates would have allowed (e.g. cargo check), returns retry: true so the model gets a second shot.
Execute
The tool call runs.
PostToolUse
Track + scan
Successful asks queue for promotion to settings.json. Write/Edit bodies pass the Tier 2 anti-pattern scanner; nudges ride on additionalContext.

Gemini CLI · deprecated

One hook. No subagent, classifier, or post output.

Google's consumer Gemini CLI sunset date was 2026-06-18. tool-gates retains this client for existing integrations; new setups should use Antigravity, Google's successor CLI, below.

tool-call lifecycle · Gemini CLI · v0.36.0+
Tool call
run_shell_command, write_file, replace, read_file, glob, grep_search, activate_skill, mcp_*. Auto-detected from hook_event_name.
BeforeTool
Decide
Same engine as Claude's PreToolUse: tree-sitter parse, gate dispatch, settings merge. Wire format: flat decision + reason. On a block, recovery is appended to the agent-facing reason and names Gemini's read_file only for a confirmed source file. Nonblocking hints and Tier 3 warnings use the user-facing systemMessage; Gemini's BeforeTool path does not consume additionalContext. Tool Gates emits "block" for hard blocks, Gemini also accepts "deny", and exit code 2 blocks. ask requires Gemini CLI v0.36.0+.
Execute
The tool call runs.

Codex CLI

Three hooks. Strict wire format; hints move to PostToolUse.

tool-call lifecycle · Codex CLI
Tool call
Bash, apply_patch (carries the unified diff in tool_input.command), mcp__*. Selected via --client codex baked into the hook command; Codex shares Claude's event names.
PreToolUse
Decide (deny only)
Codex rejects plain permissionDecision: "allow" and "ask"; allow is accepted only with updatedInput. Tool Gates does not auto-run ask-level rewrites, so every non-deny emits empty stdout and hands the decision back to Codex. Hard blocks emit permissionDecision: "deny" with a required nonempty permissionDecisionReason; recovery stays separate in supported PreToolUse additionalContext. Because Codex has no registered read tool, file recovery uses a conditional bat range example. Whether the user is prompted is governed by Codex's approval_policy; see the Codex approval model.
PermissionRequest
on confirmation prompt
Allow / deny only
Codex accepts only hookSpecificOutput.decision.behavior (allow or deny) plus an optional deny message. Other fields (like addDirectories, updatedInput, updatedPermissions, and interrupt) are not just dropped: they are treated as unsupported, causing Codex's parser to reject the hook output as invalid. tool-gates actively strips them to maintain compatibility.
Execute
The tool call runs.
PostToolUse
Track, scan, hint
Tier 2 anti-pattern nudges land here. Modern-CLI hints and Tier 3 warnings also ride this hook on Codex (a tool-gates routing choice; Codex itself accepts additionalContext on PreToolUse too). Codex's PostToolUse rejects fields like updatedMCPToolOutput as unsupported, which causes validation failures. tool-gates strips them dynamically. No PermissionDenied event because Codex has no auto-mode classifier yet.

On Codex, a tool-gates ask only becomes a prompt under approval_policy = "untrusted". Codex's built-in safe-read list, the execpolicy lever that routes those reads through tool-gates, and the two settings that silently disable prompting are covered in the Codex approval model.

Antigravity CLI (agy)

One hook. Distinct payload shape; flat decision.

tool-call lifecycle · Antigravity CLI · agy
Tool call
run_command, view_file, write_to_file, replace_file_content, multi_replace_file_content, grep_search, find_by_name. The payload nests the tool under toolCall.name with PascalCase args (the command lives at toolCall.args.CommandLine) and carries no hook_event_name. Selected via --client antigravity baked into the hook command; tool-gates normalizes the payload into its canonical shape before the engine runs.
PreToolUse
Decide
Same engine as Claude's PreToolUse: tree-sitter parse, gate dispatch, file guards on reads/writes, and Tier 1 source-file secret denies on write content. Wire format: a flat {decision, reason} object emitted only to tighten, where decision is ask or deny. Deny recovery is folded into reason; confirmed source-file recovery names Antigravity's view_file. The hard-ask floor (pipe-to-shell, eval) emits force_ask so it always prompts, even past an "Always Allow" grant. Antigravity keeps the strictest of the hook and native decisions, so the hook only tightens: a hook allow is the lowest rank and inert, so tool-gates emits nothing for it (prompt-free safe commands come from agy's native permissions.allow, generated by tool-gates agy allowlist). Allow and "no opinion" both emit nothing so Antigravity's own permission engine decides, and tool-gates never speaks for a command it does not recognize (the schema marks decision required; deferring via empty output is currently-undocumented behavior).
Execute
The tool call runs.

Antigravity drives the whole gate from one PreToolUse hook. It also exposes PostToolUse, PreInvocation, PostInvocation, and Stop, but its post payload carries no tool name or input and it has no PermissionRequest event, so PreToolUse is the entire gate. Its hooks.json is a top-level object keyed by hook name ({"tool-gates": {"PreToolUse": [...]}}), unlike the flat event map the other clients use.

Reference

Why four hooks?

Each one closes a specific gap the others leave open. None is redundant.

PreToolUse

The main gate. Bash / Monitor, Read / Write / Edit, Glob / Grep, MCP, and Skill calls pass through and get a decision back.

Also injects modern-CLI hints via additionalContext, blocks Tier 1 secrets in source Write/Edit bodies, and enforces file guards on symlinked AI-config files like CLAUDE.md and .cursorrules.

PermissionRequest

Claude's subagents ignore PreToolUse's allow. This hook re-runs the gate for them so the same policy applies to delegated work.

Also fires when Claude's resolver wants to ask about a path outside cwd; tool-gates can promote that to deny if the engine knows the call is dangerous.

PermissionDenied

Auto mode runs a server-side classifier instead of prompting the human. The classifier sometimes denies calls tool-gates would allow.

tool-gates re-checks. If the engine agrees the call is safe, this hook returns retry: true and the model tries again. Requires Claude Code 2.1.88+.

PostToolUse

Fires after the call runs. Used for approval learning (queue successful asks) and Tier 2 anti-pattern nudges on Write/Edit content.

On Codex, tool-gates currently carries Tier 3 informational warnings and modern-CLI hints here rather than on PreToolUse.

Reasoning Effort level. In newer versions of the CLI, an effort field (Zod object { level: "adaptive" | "low" | "medium" | "high" }) is injected into all hook event payloads, conveying the active turn's reasoning intensity.

Gemini CLI and Antigravity CLI each install one pre-execution hook. Codex CLI has no PermissionDenied event (no auto-mode classifier yet). The engine routes around what's missing. Gemini sends block recovery to the agent in reason and nonblocking hints or Tier 3 warnings to the user in systemMessage. Codex moves non-deny context to PostToolUse but can carry deny recovery in PreToolUse additionalContext. Antigravity's Pre output has no additionalContext field, so hints and Tier 3 warnings are dropped there while deny recovery is folded into reason.

tool-gates · permission gate hook for Claude Code, Codex CLI, and Antigravity CLI, with deprecated Gemini CLI support. github.com/camjac251/tool-gates

13 gates · 400+ commands · built from rules/*.toml