docs/hooks/index.md
Hooks are scripts or programs that Gemini CLI executes at specific points in the agentic loop, allowing you to intercept and customize behavior without modifying the CLI's source code.
Hooks run synchronously as part of the agent loop—when a hook event fires, Gemini CLI waits for all matching hooks to complete before continuing.
With hooks, you can:
Hooks are triggered by specific events in Gemini CLI's lifecycle.
| Event | When It Fires | Impact | Common Use Cases |
|---|---|---|---|
SessionStart | When a session begins (startup, resume, clear) | Inject Context | Initialize resources, load context |
SessionEnd | When a session ends (exit, clear) | Advisory | Clean up, save state |
BeforeAgent | After user submits prompt, before planning | Block Turn / Context | Add context, validate prompts, block turns |
AfterAgent | When agent loop ends | Retry / Halt | Review output, force retry or halt execution |
BeforeModel | Before sending request to LLM | Block Turn / Mock | Modify prompts, swap models, mock responses |
AfterModel | After receiving LLM response | Block Turn / Redact | Filter/redact responses, log interactions |
BeforeToolSelection | Before LLM selects tools | Filter Tools | Filter available tools, optimize selection |
BeforeTool | Before a tool executes | Block Tool / Rewrite | Validate arguments, block dangerous ops |
AfterTool | After a tool executes | Block Result / Context | Process results, run tests, hide results |
PreCompress | Before context compression | Advisory | Save state, notify user |
Notification | When a system notification occurs | Advisory | Forward to desktop alerts, logging |
Understanding these core principles is essential for building robust hooks.
Hooks communicate via stdin (Input) and stdout (Output).
stdout other than the final JSON object. Even a single echo or print
call before the JSON will break parsing.stdout contains non-JSON text, parsing will
fail. The CLI will default to "Allow" and treat the entire output as a
systemMessage.stderr for all logging and debugging (for
example, echo "debug" >&2). Gemini CLI captures stderr but never attempts
to parse it as JSON.Gemini CLI uses exit codes to determine the high-level outcome of a hook execution:
| Exit Code | Label | Behavioral Impact |
|---|---|---|
| 0 | Success | The stdout is parsed as JSON. Preferred code for all logic, including intentional blocks (for example, {"decision": "deny"}). |
| 2 | System Block | Critical Block. The target action (tool, turn, or stop) is aborted. stderr is used as the rejection reason. High severity; used for security stops or script failures. |
| Other | Warning | Non-fatal failure. A warning is shown, but the interaction proceeds using original parameters. |
You can filter which specific tools or triggers fire your hook using the
matcher field.
BeforeTool, AfterTool): Matchers are Regular
Expressions. (for example, "write_.*")."startup")."*" or "" (empty string) matches all occurrences.Hooks are configured in settings.json. Gemini CLI merges configurations from
multiple layers in the following order of precedence (highest to lowest):
.gemini/settings.json in the current directory.~/.gemini/settings.json./etc/gemini-cli/settings.json.{
"hooks": {
"BeforeTool": [
{
"matcher": "write_file|replace",
"hooks": [
{
"name": "security-check",
"type": "command",
"command": "$GEMINI_PROJECT_DIR/.gemini/hooks/security.sh",
"timeout": 5000
}
]
}
]
}
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | The execution engine. Currently only "command" is supported. |
command | string | Yes* | The shell command to execute. (Required when type is "command"). |
name | string | No | A friendly name for identifying the hook in logs and CLI commands. |
timeout | number | No | Execution timeout in milliseconds (default: 60000). |
description | string | No | A brief explanation of the hook's purpose. |
Hooks are executed with a sanitized environment.
GEMINI_PROJECT_DIR: The absolute path to the project root.GEMINI_PLANS_DIR: The absolute path to the plans directory.GEMINI_SESSION_ID: The unique ID for the current session.GEMINI_CWD: The current working directory.CLAUDE_PROJECT_DIR: (Alias) Provided for compatibility.[!WARNING] Hooks execute arbitrary code with your user privileges. By configuring hooks, you are allowing scripts to run shell commands on your machine.
Project-level hooks are particularly risky when opening untrusted projects.
Gemini CLI fingerprints project hooks. If a hook's name or command changes
(for example, via git pull), it is treated as a new, untrusted hook and
you will be warned before it executes.
See Security Considerations for a detailed threat model.
Use the CLI commands to manage hooks without editing JSON manually:
/hooks panel/hooks enable-all or /hooks disable-all/hooks enable <name> or /hooks disable <name>