# Gemini CLI hooks

> Hooks are scripts or programs that Gemini CLI executes at specific points in the agentic loop, allowing you to intercept…

- 网址：https://funcoding.ai/agents/gemini-cli/hooks/
- 来源：Gemini CLI 官方文档原文（英文），Apache-2.0 许可，同步于 2026-10-11
- 官方原文：https://geminicli.com/docs/hooks/

---
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.

## What are hooks?

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:

- **Add context:** Inject relevant information (like git history) before the
  model processes a request.
- **Validate actions:** Review tool arguments and block potentially dangerous
  operations.
- **Enforce policies:** Implement security scanners and compliance checks.
- **Log interactions:** Track tool usage and model responses for auditing.
- **Optimize behavior:** Dynamically filter available tools or adjust model
  parameters.

### Getting started

- **[Writing hooks guide](https://geminicli.com/docs/hooks/writing-hooks)**: A tutorial on creating
  your first hook with comprehensive examples.
- **[Best practices](https://geminicli.com/docs/hooks/best-practices)**: Guidelines on security,
  performance, and debugging.
- **[Hooks reference](https://funcoding.ai/agents/gemini-cli/hooks/reference/)**: The definitive technical
  specification of I/O schemas and exit codes.

## Core concepts

### Hook events

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           |

### Global mechanics

Understanding these core principles is essential for building robust hooks.

#### Strict JSON requirements (The "Golden Rule")

Hooks communicate via `stdin` (Input) and `stdout` (Output).

1. **Silence is Mandatory**: Your script **must not** print any plain text to
   `stdout` other than the final JSON object. **Even a single `echo` or `print`
   call before the JSON will break parsing.**
2. **Pollution = Failure**: If `stdout` contains non-JSON text, parsing will
   fail. The CLI will default to "Allow" and treat the entire output as a
   `systemMessage`.
3. **Debug via Stderr**: Use `stderr` for **all** logging and debugging (for
   example, `echo "debug" >&2`). Gemini CLI captures `stderr` but never attempts
   to parse it as JSON.

#### Exit codes

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.                                                                               |

#### Matchers

You can filter which specific tools or triggers fire your hook using the
`matcher` field.

- **Tool events** (`BeforeTool`, `AfterTool`): Matchers are **Regular
  Expressions**. (for example, `"write_.*"`).
- **Lifecycle events**: Matchers are **Exact Strings**. (for example,
  `"startup"`).
- **Wildcards**: `"*"` or `""` (empty string) matches all occurrences.

## Configuration

Hooks are configured in `settings.json`. Gemini CLI merges configurations from
multiple layers in the following order of precedence (highest to lowest):

1.  **Project settings**: `.gemini/settings.json` in the current directory.
2.  **User settings**: `~/.gemini/settings.json`.
3.  **System settings**: `/etc/gemini-cli/settings.json`.
4.  **Extensions**: Hooks defined by installed extensions.

### Configuration schema

```json
{
  "hooks": {
    "BeforeTool": [
      {
        "matcher": "write_file|replace",
        "hooks": [
          {
            "name": "security-check",
            "type": "command",
            "command": "$GEMINI_PROJECT_DIR/.gemini/hooks/security.sh",
            "timeout": 5000
          }
        ]
      }
    ]
  }
}
```

#### Hook configuration fields

| 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.                           |

---

### Environment variables

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.

## Security and risks

<!-- prettier-ignore -->

<div class="callout callout-warning">

Hooks execute arbitrary code with your user privileges. By
configuring hooks, you are allowing scripts to run shell commands on your
machine.

</div>

**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](https://geminicli.com/docs/hooks/best-practices#using-hooks-securely)
for a detailed threat model.

## Managing hooks

Use the CLI commands to manage hooks without editing JSON manually:

- **View hooks:** `/hooks panel`
- **Enable/Disable all:** `/hooks enable-all` or `/hooks disable-all`
- **Toggle individual:** `/hooks enable <name>` or `/hooks disable <name>`
