# GitHub Copilot 挂钩参考

在 Copilot CLI 和 Copilot cloud agent 中查找挂钩事件、配置格式以及挂钩的输入有效载荷。

## 介绍

挂钩是在会话期间的特定生命周期点执行的外部命令，可用于自定义自动化、安全控制和集成。

挂钩在两个 Copilot 界面中受支持：Copilot CLI 和 Copilot cloud agent。 大多数配置格式和事件有效负载相同，但执行环境和可以触发的事件集有所不同。

在本文中，两个界面之间行为不同的情况会通过“仅 CLI”和“仅云智能体”注释进行标注。 未标记的任何内容都适用于这两者。

## 挂钩位置

挂钩运行的位置以及存储挂钩配置文件的位置取决于表面：

* **Copilot CLI** — 挂钩在开发人员的本地计算机上运行，其 shell 与 CLI 相同。 CLI 支持本文中所述的所有挂钩事件。

  钩子按以下顺序从这些源加载（策略，然后用户，然后项目，然后插件）并进行合并。 当同一事件出现在多个源中时，将运行来自所有源的所有挂钩条目。

  * **策略级挂钩文件** — 平台适当的策略目录中的 JSON 文件，按字母顺序加载。 策略钩子在整个计算机范围内生效，并且会在所有其他钩子之前加载。 它们不能被禁用 `disableAllHooks` ，无论文件夹信任状态如何，都可用。 请参阅下文的 [策略钩子](#policy-hooks)。
  * **存储库级挂钩文件** - `.github/hooks/*.json` 在存储库根目录中。
  * **用户级挂钩文件** - `*.json` 用户级挂钩目录中的文件。 默认情况下，macOS 和 Linux 上的 `~/.copilot/hooks/`，或 Windows 上的 `%USERPROFILE%\.copilot\hooks\`。 如果 `COPILOT_HOME` 已设置，则为 `$COPILOT_HOME/hooks/`.
  * ```
              存储库设置中的**内联 `hooks` 代码块** — 存储库中 `hooks`（已提交至 Git）或 `.github/copilot/settings.json`（通常被 Git 忽略且与用户相关）顶层中的 `.github/copilot/settings.local.json` 字段。 存储库中的跨工具 `.claude/settings.json` 和 `.claude/settings.local.json` 文件也会被读取。
    ```
  * ```
              用户级配置中的**内联 `hooks` 代码块** — 位于 `hooks` 顶层的 `~/.copilot/settings.json` 字段。
    ```
  * **已安装插件提供的挂钩** — 由每个插件在其安装目录内的 `hooks.json`（或 `hooks/hooks.json` 之下）中声明。

* **Copilot cloud agent** — 挂钩在云代理为每个作业预配的临时 Linux 沙盒内运行。 沙盒是非交互式的，具有受约束的网络，并在作业结束时销毁。 仅触发部分事件，且仅处理 `bash`（或 `command`）条目。

  挂钩配置被加载自克隆存储库中的 `.github/hooks/*.json` 文件。

### 策略钩子

> \[!NOTE]
> **Copilot CLI 仅限于此。** 在 Copilot cloud agent 下，不支持策略钩子。

策略钩子是由管理员加载的、作用于整个计算机的钩子。 它们在所有其他钩子之前加载，且无法通过 `disableAllHooks` 禁用。

策略钩子来自两个来源：

* **文件系统**：平台适当的策略目录中的 JSON 文件，按字母顺序加载：
  * Linux/macOS： `/etc/github-copilot/policy.d/*.json`
  * Windows： `C:\ProgramData\GitHub\Copilot\policy.d\*.json`
* **Windows 注册表**：`HKLM\Software\Policies\GitHub\Copilot` 下的值（每个子项都包含一个 `Policy` REG\_SZ 值，其中含有 JSON 策略文档）。

策略挂钩文件使用与用户和项目挂钩相同的挂钩配置格式（`{ "version": 1, "hooks": { ... } }`）。 在 POSIX 系统上，策略文件必须由 root 拥有，且不能被组或其他用户写入。

策略钩子旨在供企业 IT 管理员使用，安装时需要提升权限。 最终用户无法修改它们。

## 云代理执行环境

本节仅适用于**Copilot cloud agent**。 它描述了影响您编写挂钩脚本以及为云智能体任务配置挂钩条目的限制条件。

| 财产                                                               | 值                                                                                                            |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| 操作系统                                                             | Linux。 仅命令挂钩中的 `bash` 字段会被采纳；`powershell` 条目将被忽略。 跨平台 `command` 字段被视为备用方案。                                   |
| 工作目录                                                             |                                                                                                              |
| `/workspace` 克隆存储库时，否则为 `/root`。 在挂钩条目上设置 `cwd` 或从脚本引用文件时使用此路径。  |                                                                                                              |
| Filesystem                                                       | 短暂。 作业结束时，将丢弃由钩子写入的文件（例如日志、CSV 和转录文件）。 若要保留挂钩输出，请通过 `http` 挂钩条目发送它。                                          |
| 出站网络                                                             | 受云代理防火墙限制。 默认情况下，只有GitHub和Copilot主机名可访问;访问任何其他主机（例如`https://hooks.example.com`）需要管理员配置的防火墙允许规则。              |
| 可用的环境变量                                                          |                                                                                                              |
| `GITHUB_COPILOT_API_TOKEN` 和 `GITHUB_COPILOT_GIT_TOKEN` 被设置在沙盒中。 |                                                                                                              |
| `COPILOT_AGENT_PROMPT` 包含调用该任务时的提示信息。                            |                                                                                                              |
| `HOME` 被设置为 `/root`，因此任何解析 `~/...` 路径的挂钩脚本会写入到临时沙箱中。             |                                                                                                              |
| `GITHUB_TOKEN` 未设置。                                              |                                                                                                              |
| 交互性                                                              | 完全非交互式。 代理使用预先授予的所有工具权限运行，因此不会显示任何权限对话框，并且不会向用户显示任何通知。                                                       |
| 配置发现                                                             | 在云代理作业中，默认存在的唯一挂钩配置位于 `.github/hooks/*.json` 克隆的存储库中。 沙盒中不包含用户级别的挂钩文件、`settings.json`、`config.json` 或已安装的插件。 |

## 钩子配置格式

挂钩配置文件使用 JSON 格式和版本 `1`。

> \[!NOTE]
> 如果从目录（例如， `.github/hooks/`）加载的挂钩配置文件包含格式不正确的挂钩项，则仅删除并记录该项 — 同一文件中的有效同级挂钩仍会加载。 结构错误（JSON 无效、错误 `version`或非数组事件列表）仍会拒绝整个文件。 在 `settings.json` 中内联定义的钩子仍保持严格：任何条目级验证错误都会导致整个 `hooks` 字段被拒绝。 其他配置文件始终独立加载。

### 命令挂钩

命令挂钩运行 shell 脚本，在所有挂钩类型上都受支持。

> \[!NOTE]
> **仅限云代理。** 云代理在 Linux 沙盒中运行挂钩。 仅采纳`bash`字段;`powershell`条目将被忽略。 跨平台 `command` 字段被视为备用方案。

```json
{
  "version": 1,
  "hooks": {
    "preToolUse": [
      {
        "type": "command",
        "bash": "YOUR_BASH_COMMAND",
        "powershell": "YOUR_POWERSHELL_COMMAND",
        "cwd": "OPTIONAL/WORKING/DIRECTORY",
        "env": { "VAR": "VALUE" },
        "timeoutSec": 30
      }
    ]
  }
}
```

| 领域                                                                       | 类型                                                                                   | 必需 | Description                |
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | -- | -------------------------- |
| `bash`                                                                   | 字符串                                                                                  |    |                            |
| `bash`、`powershell`或 `command` 之一                                        | Unix 的 Shell 命令。                                                                     |    |                            |
| `command`                                                                | 字符串                                                                                  |    |                            |
| `bash`、`powershell`或 `command` 之一                                        | 跨平台回退。 当这些字段缺失时，将复制到 `bash` 和 `powershell`；在各自的平台上，显式指定的 `bash` 或 `powershell` 条目优先。 |    |                            |
| `cwd`                                                                    | 字符串                                                                                  | 否  | 命令的工作目录（相对于存储库根目录或绝对目录）。   |
| `env`                                                                    | 对象                                                                                   | 否  | 要设置的环境变量（支持变量扩展）。          |
| `powershell`                                                             | 字符串                                                                                  |    |                            |
| `bash`、`powershell`或 `command` 之一                                        | 适用于 Windows 的 Shell 命令。                                                              |    |                            |
| `timeout`                                                                | number                                                                               | 否  |                            |
| `timeoutSec` 的别名，单位为秒。 仅在不存在时 `timeoutSec` 使用; `timeoutSec` 当两者都存在时优先使用。 |                                                                                      |    |                            |
| `timeoutSec`                                                             | number                                                                               | 否  | 超时（以秒为单位）。 默认值：`30`。       |
| `type`                                                                   | `"command"`                                                                          | 否  | 挂钩类型。 省略时，默认为 `"command"`。 |

#### 进度消息

命令钩子在执行时可以向 CLI 时间线中输出进度状态行。 在编写最终输出之前，将 `{"type": "progress", "message": "..."}` JSON 对象写入 stdout：

```bash
echo '{"type": "progress", "message": "Checking policy..."}'
# ... perform work ...
echo '{"permissionDecision": "allow"}'
```

将 `"temporary": true` 设置为输出临时状态行。 临时条目会替换之前的临时条目，并会在助手作出响应时被清除，而不是累积在时间线中：

```bash
echo '{"type": "progress", "message": "Routing...", "temporary": true}'
echo '{"type": "progress", "message": "Thinking...", "temporary": true}'
# ... perform work ...
echo '{"permissionDecision": "allow"}'
```

进度消息仅用于显示，不会影响 Hook 输出或决策逻辑。

**当 stdout 中夹杂进度消息时，如何解析 stdout。** — CLI 在钩子运行时逐行扫描 stdout。 任何在修剪后是以单个完整 JSON 对象形式存在且包含 `"type": "progress"` 的行，都将作为进度事件被消耗并**从钩子的输出流中移除**。 其余各行——空白行、纯文本以及非进度消息的 JSON 对象——均按原样保留。 当钩子退出时，保留的各行会被拼接起来、去除首尾空白，并通过一次 `JSON.parse` 调用进行解析：其结果就是钩子的输出（即本文其他部分提到的“钩子输出 JSON”）。 这意味着：

* 与最终决策对象一起发出进度线（如上例所示）是安全的，并且是预期模式-进度线永远不会到达 JSON 分析器。
* 每个进度消息都必须单独占一行，且该行内容本身必须是有效的 JSON。 多行 / 美化打印的进度对象不会被识别为进度，将留在输出流中，这很可能导致最终的 `JSON.parse` 失败。
* 相比之下，最终的决策对象可能跨越多行 — 仅进度*识别*是面向行的；进度剥离后剩下的内容将作为一个 JSON 文档进行解析，而不是作为换行符分隔的 JSON。
* 如果剩余输出为空或无法分析为 JSON，则挂钩被视为未生成任何输出，并跌至默认行为。 因此，stdout 上出现两个或更多非进度 JSON 对象（例如，两次 `echo '{"permissionDecision": ...}'` 调用）将拼接成无效的 JSON 并被忽略 — 请精确地发出一个最终决策对象。

### HTTP 钩子

HTTP 挂钩将输入有效负载作为 JSON `POST` 发送到 URL。

> \[!NOTE]
>
> * 默认情况下，仅允许 `https://` URL。 非 TLS `http://` 请求会被拒绝，但当设置了 `http://localhost` 时，`http://127.*`、`http://[::1]` 和 `COPILOT_HOOK_ALLOW_LOCALHOST=1` 除外。
> *

**仅限云代理。** 来自沙盒的出站网络受云代理防火墙的限制，因此 `url` 必须面向在允许列表中的主机。

```json
{
  "version": 1,
  "hooks": {
    "postToolUse": [
      {
        "type": "http",
        "url": "https://hooks.example.com/copilot",
        "headers": { "X-Source": "copilot-cli" },
        "allowedEnvVars": ["GITHUB_TOKEN"],
        "timeoutSec": 30
      }
    ]
  }
}
```

| 领域                                                                       | 类型        | 必需 | Description                                                                                        |
| ------------------------------------------------------------------------ | --------- | -- | -------------------------------------------------------------------------------------------------- |
| `allowedEnvVars`                                                         | string\[] | 否  | 环境变量名称可在 `headers` 值内扩展。 设置时， `url` 必须使用 `https://`。                                               |
| `headers`                                                                | 对象        | 否  | 要包含的请求头。                                                                                           |
| `timeout`                                                                | number    | 否  |                                                                                                    |
| `timeoutSec` 的别名，单位为秒。 仅在不存在时 `timeoutSec` 使用; `timeoutSec` 当两者都存在时优先使用。 |           |    |                                                                                                    |
| `timeoutSec`                                                             | number    | 否  | 超时（以秒为单位）。 默认值：`30`。                                                                               |
| `type`                                                                   | `"http"`  | 是的 | 必须是 `"http"`。                                                                                      |
| `url`                                                                    | 字符串       | 是的 | 目标 URL。 必须使用`http:`或`https:`。 对于 `preToolUse` 和 `permissionRequest`，必须使用 `https://` ，因为响应可以授予工具权限。 |

### 提示挂钩

提示挂钩自动提交文本，就像用户键入文本一样。 它们仅受支持于`sessionStart`。 文本可以是自然语言提示或斜杠命令。

> \[!NOTE]
> **Copilot CLI 仅限于此。** 提示挂钩仅在**新的交互式会话**时触发。 它们不会在恢复时触发，也不会在非交互式提示模式 (`-p`) 下触发。

> \[!NOTE]
> **云代理。** 云代理作业以非交互方式运行（类似于 `-p`），因此 `prompt` 挂钩条目可能不会触发。 在依赖它们之前，请确认它们在您的环境中的行为。

```json
{
  "version": 1,
  "hooks": {
    "sessionStart": [
      {
        "type": "prompt",
        "prompt": "YOUR_PROMPT_TEXT_OR_SLASH_COMMAND"
      }
    ]
  }
}
```

| 领域       | 类型         | 必需 | Description           |
| -------- | ---------- | -- | --------------------- |
| `type`   | `"prompt"` | 是的 | 必须是 `"prompt"`。       |
| `prompt` | 字符串        | 是的 | 要提交的文本可以是自然语言消息或斜杠命令。 |

## 挂钩事件

下表列出了每个受支持的事件。
**“云代理**”列显示事件是否在云代理下触发，并记录任何行为差异。

| 事件                                                                                         | 在以下情况下触发                                                                                                                                                                                                                                                                                                                       | 已处理的输出                                              | 云代理                                                           |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- | ------------------------------------------------------------- |
| `agentStop`                                                                                | 主要代理完成一回合。                                                                                                                                                                                                                                                                                                                     | 是 — 可以阻止和强制继续。                                      | 火灾。                                                           |
| `decision: "block"` 强制进行另一轮操作，这仍计入作业的超时时间。                                                 |                                                                                                                                                                                                                                                                                                                                |                                                     |                                                               |
| `errorOccurred`                                                                            | 执行期间发生错误。                                                                                                                                                                                                                                                                                                                      | 否                                                   | 火灾。                                                           |
| `notification`                                                                             | 当 CLI 发出系统通知（shell 完成、代理完成或空闲、权限提示、启发对话框）时异步触发。 即发即弃：从不阻止会话。 在 `matcher` 上支持 `matcher` 正则表达式模式（`notification_type` 字段的值）。                                                                                                                                                                                                      | 可选：可以将 `additionalContext` 注入到会话中。                  |                                                               |
| **不触发。** 云代理不会向用户显示通知（请参阅上面的云代理执行环境表中的 **交互** 行）。                                          |                                                                                                                                                                                                                                                                                                                                |                                                     |                                                               |
| `permissionRequest`                                                                        | 在权限服务运行之前触发（规则引擎、会话审批、自动允许/自动拒绝和用户提示）。 如果合并后的挂钩输出返回 `behavior: "allow"` 或 `"deny"`，该决定会直接短路正常的权限流程——但沙盒绕过请求除外（`requestSandboxBypass: true`）；对于这类请求，`allow` 并不构成对沙盒逃逸的预先批准，只有 `deny` 会向下传递（请参阅 [`permissionRequest` 决策控制](#permissionrequest-decision-control) 中关于沙盒绕过的例外）。 在 `matcher` 上支持 `matcher` 正则表达式模式（`toolName` 字段的值）。 | 是 — 可以以编程方式允许或拒绝。                                   | 工具调用已预先批准，因此此挂钩要么不触发，要么无效。 改为使用 `preToolUse` 来做权限决策。          |
| `postToolUse`                                                                              | 每个工具成功完成操作后。                                                                                                                                                                                                                                                                                                                   | 是 — 可以修改工具结果或为模型注入其他上下文。                            | 火灾。                                                           |
| `postToolUseFailure`                                                                       | 工具以失败告终后。                                                                                                                                                                                                                                                                                                                      | 是 - 可以通过 `additionalContext`（命令挂钩的退出代码 `2`）提供恢复指导。  | 火灾。                                                           |
| `preCompact`                                                                               | 上下文压缩即将开始（手动或自动）。 支持使用 `matcher` 正则表达式模式（`matcher` 字段的值）按触发器（`"manual"` 或 `"auto"`）进行筛选。                                                                                                                                                                                                                                       | 否 - 仅通知。                                            | 仅在满足 `trigger: "auto"` 条件时触发。 没有用户请求手动压缩。                     |
| `preToolUse`                                                                               | 在每个工具执行之前。                                                                                                                                                                                                                                                                                                                     | 是 — 可以允许、拒绝或修改。                                     | 火灾。 由于没有用户可以回答，`"ask"` 的决策被视为 `"deny"`。                       |
| `sessionEnd`                                                                               | 会话终止。                                                                                                                                                                                                                                                                                                                          | 否                                                   | 每个作业触发一次。                                                     |
| `reason` 通常是 `"complete"`， `"error"`或 `"timeout"`; `"abort"` ，并且 `"user_exit"` 不需要，因为没有用户。 |                                                                                                                                                                                                                                                                                                                                |                                                     |                                                               |
| `sessionStart`                                                                             | 新的或已恢复的会话开始。                                                                                                                                                                                                                                                                                                                   | 可选：可以将 `additionalContext` 注入到会话中。                  | 每个任务仅触发一次，作为新会话（而非恢复）。 有关云智能体下 `prompt` 条目的行为，请参阅上文的“提示挂钩”说明。 |
| `subagentStart`                                                                            | 子代理在运行之前生成。 支持使用`matcher`正则表达式模式（即 `matcher` 字段的值）按代理名称进行筛选。                                                                                                                                                                                                                                                                   | 可选 — 无法阻止创建，但 `additionalContext` 会作为前缀添加到子智能体的提示中。 | 火灾。                                                           |
| `subagentStop`                                                                             | 子代理完成。                                                                                                                                                                                                                                                                                                                         | 是 — 可以阻止和强制继续。                                      | 火灾。                                                           |
| `userPromptSubmitted`                                                                      | 用户提交提示。                                                                                                                                                                                                                                                                                                                        | 可选——`modifiedPrompt` 仅被 SDK 编程钩子识别。                 | 最多触发一次，针对提供给该任务的提示。 没有后续用户输入。                                 |
| `userPromptTransformed`                                                                    | 在运行时将已提交的提示转换为模型可见内容之后、该内容被输出并保存到会话历史记录之前触发。 对主消息以及批量提交中之前的每条消息运行。 仅变更——它可以重写模型接收到的内容，但不能阻止或处理该轮交互。 系统通知永远不会触发它。                                                                                                                                                                                                               | 是 — 可以重写面向模型的内容。                                    | 火灾。                                                           |

## 挂钩事件输入有效负载

每个挂钩事件将 JSON 有效负载传递到挂钩处理程序。 支持两种负载格式，可根据挂钩配置中使用的事件名称进行选择。

* **camelCase 格式** - 在 camelCase 中配置事件名称（例如）。 `sessionStart` 字段使用 camelCase。
* **VS Code兼容格式** - 在 PascalCase 中配置事件名称（例如）。 `SessionStart` 字段使用 snake\_case 来匹配 VS CodeCopilot 扩展格式。

### `sessionStart` / `SessionStart`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;      // Unix timestamp in milliseconds
    cwd: string;
    source: "startup" | "resume" | "new";
    initialPrompt?: string;
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "SessionStart";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    source: "startup" | "resume" | "new";
    initial_prompt?: string;
}
```

### `sessionEnd` / `SessionEnd`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    reason: "complete" | "error" | "abort" | "timeout" | "user_exit";
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "SessionEnd";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    reason: "complete" | "error" | "abort" | "timeout" | "user_exit";
}
```

### `userPromptSubmitted` / `UserPromptSubmit`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    prompt: string;
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "UserPromptSubmit";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    prompt: string;
}
```

**Output:**

```typescript
{
    modifiedPrompt?: string; // Replaces the prompt for the rest of the turn (SDK programmatic hooks only)
}
```

返回 `{}` 或为空以保持提示不变。

> \[!NOTE]
> \*
> `modifiedPrompt` 仅对 SDK 的程序化钩子生效。 命令和 HTTP 配置文件 `userPromptSubmitted` 钩子的输出会被丢弃，包括 `modifiedPrompt`。 用于托管或引导 Copilot cloud agent 会话的更轻量的钩子处理运行时也会忽略它。 这是与 `preToolUse` 相同的运行时拆分。
>
> * 非字符串的 `modifiedPrompt`、`modifiedTransformedPrompt` 或经过处理的 `responseContent` 值会被忽略，而不会破坏会话——系统会记录一条指明该字段名称的类型警告，并将其作为 `session.warning` 事件发出。 系统会拒绝将覆盖值设为空字符串，而不是清空面向模型的内容。 值 `null``additionalContext` 被视为不存在，而不是被注入为文本文本 `null`。 挂钩输出（命令挂钩的 stdout，HTTP 挂钩的响应正文）每次调用的上限为 10 MiB；超出该大小的响应将被截断，而不会耗尽内存。

### `userPromptTransformed`

在运行时将已提交的提示转换为模型可见内容之后、该内容被输出并保存到会话历史记录之前触发。 对主消息以及批量提交中之前的每条消息运行。 仅变更——它可以重写模型接收到的内容，但不能拦截或处理该轮对话。 系统通知永远不会触发它。

**输入：**

```typescript
{
    sessionId: string;
    timestamp: number;         // epoch-ms integer
    cwd: string;
    prompt: string;            // user prompt after userPromptSubmitted hooks have run
    transformedPrompt: string; // runtime-transformed content the model will receive
}
```

**Output:**

```typescript
{
    modifiedTransformedPrompt?: string; // Replaces the model-facing content
}
```

返回 `{}` 或为空，使转换的内容保持不变。
`modifiedTransformedPrompt` 仅替换发送到模型并存储在会话历史记录中的内容（时间线中显示的提示不受影响），如果恢复会话，则替换将保持不变。

### `preToolUse` / `PreToolUse`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    toolName: string;
    toolArgs: unknown;
}
```

\*\*
VS Code 兼容的输入：\*\*

配置了 PascalCase 事件名称 `PreToolUse` 后，有效负载会使用 snake\_case 字段名称来匹配 VS CodeCopilot 扩展格式：

```typescript
{
    hook_event_name: "PreToolUse";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    tool_name: string;
    tool_input: unknown;    // Tool arguments (parsed from JSON string when possible)
}
```

**Claude 格式匹配器（PascalCase `PreToolUse`）：** 使用 PascalCase 事件名称 `PreToolUse` 配置的钩子（如 Claude Code 插件和 Open Plugins 格式中所用）采用 Claude 的匹配器语义，而不是原生正则表达式规则：

* ```
            对于每个工具，`*`、`**` 或空的 `matcher` 值都会触发。
  ```
* 字面名称或 `|` 分隔的择一匹配（例如 `Bash` 或 `Edit|Write`）会在任何令牌等于运行时工具名称或下表中 Claude 工具名称时触发。
* 任何其他值都会被视为一个区分大小写、锚定为 `^(?:PATTERN)$` 的正则表达式，并针对 Claude 工具名称进行匹配测试（对于没有对应 Claude 工具的工具，则针对其运行时名称进行测试）。

PascalCase `PreToolUse` 的有效载荷将 `tool_name` 报告为 Claude 工具名称（例如 `Bash`，而不是 `bash`）。

| 运行时工具                                     | Claude 工具名称       |
| ----------------------------------------- | ----------------- |
| `bash`、`powershell`                       | `Bash`            |
| `view`                                    | `Read`            |
| `create`                                  | `Write`           |
| `edit`、`str_replace_editor`、`apply_patch` | `Edit`            |
| `grep`、`rg`                               | `Grep`            |
| `glob`                                    | `Glob`            |
| `web_fetch`                               | `WebFetch`        |
| `web_search`                              | `WebSearch`       |
| `ask_user`                                | `AskUserQuestion` |
| `update_todo`                             | `TodoWrite`       |
| `task`                                    |                   |
| `Agent`（字面 `Task` 也被接受）                   |                   |

没有 Claude 等效的工具保留其运行时名称。

> \[!IMPORTANT]
> **`preToolUse` 的命令与 HTTP 失败行为：** 命令 `preToolUse` 挂钩在发生错误时采用**故障关闭**行为——崩溃或非零退出（包括退出 `2`）都会拒绝该工具调用，即使该挂钩的 stdout JSON 报告 `permissionDecision: "allow"`。 命令挂钩 **超时始终以故障开放方式处理，即使是对于 `preToolUse` 和管理员部署的策略挂钩**也是如此——挂钩超时后会发出警告，并允许工具调用按正常的权限流程继续进行，而不是拒绝它。 HTTP `preToolUse` 钩子是**故障开放的** — 网络错误、超时或非 2xx 响应将回退到默认的权限流。 选择符合安全要求的变体。

### `postToolUse` / `PostToolUse`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    toolName: string;
    toolArgs: unknown;
    toolResult: {
        resultType: "success";
        textResultForLlm: string;
    }
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "PostToolUse";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    tool_name: string;
    tool_input: unknown;
    tool_result: {
        result_type: "success";
        text_result_for_llm: string;
    }
}
```

### `postToolUseFailure` / `PostToolUseFailure`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    toolName: string;
    toolArgs: unknown;
    error: string;
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "PostToolUseFailure";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    tool_name: string;
    tool_input: unknown;
    error: string;
}
```

### `agentStop` / `Stop`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    transcriptPath: string;
    stopReason: "end_turn";
    stop_hook_active: boolean; // true when this turn was already forced to continue by a prior "block" decision from this hook
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "Stop";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    transcript_path: string;
    stop_reason: "end_turn";
    stop_hook_active: boolean;
}
```

### `subagentStart`

> \[!NOTE]
> 内置 `general-purpose` 代理不会发出 `subagentStart` 或 `subagentStop` 事件。 所有其他基于 YAML 的内置代理（包括`explore`、、`task``code-review`、`rubber-duck``research`和）和`security-review`用户定义的自定义代理都会发出这些事件。

**输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    transcriptPath: string;
    agentName: string;
    agentDisplayName?: string;
    agentDescription?: string;
}
```

### `subagentStop` / `SubagentStop`

在子代理正常完成时触发，然后再将结果返回到父级。
`stopReason` 当前始终为 `"end_turn"`。 此钩子会在大响应溢出处理之前触发，因此 `response`（或在与 `last_assistant_message` 兼容的格式中使用的 VS Code）包含完整的最终子代理响应文本。

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    transcriptPath: string;
    agentId: string;
    agentType: string;
    agentName: string;
    agentDisplayName?: string;
    response: string;       // Full final subagent response text
    stopReason: "end_turn";
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "SubagentStop";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    transcript_path: string;
    agent_id: string;
    agent_type: string;
    agent_name: string;
    agent_display_name?: string;
    last_assistant_message: string; // The `response` text
    stop_reason: "end_turn";
}
```

### `errorOccurred` / `ErrorOccurred`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    error: {
        message: string;
        name: string;
        stack?: string;
    };
    errorContext: "model_call" | "tool_execution" | "system" | "user_input";
    recoverable: boolean;
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "ErrorOccurred";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    error: {
        message: string;
        name: string;
        stack?: string;
    };
    error_context: "model_call" | "tool_execution" | "system" | "user_input";
    recoverable: boolean;
}
```

### `preCompact` / `PreCompact`

**camelCase 输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    transcriptPath: string;
    trigger: "manual" | "auto";
    customInstructions: string;
}
```

\*\*
VS Code 兼容的输入：\*\*

```typescript
{
    hook_event_name: "PreCompact";
    session_id: string;
    timestamp: string;      // ISO 8601 timestamp
    cwd: string;
    transcript_path: string;
    trigger: "manual" | "auto";
    custom_instructions: string;
}
```

## `preToolUse` 决策控制

挂钩 `preToolUse` 可以通过将 JSON 对象写入 stdout 来控制工具执行。

| 领域                         | 价值观                                                        | Description                 |
| -------------------------- | ---------------------------------------------------------- | --------------------------- |
| `permissionDecision`       |                                                            |                             |
| `"allow"`、`"deny"`、`"ask"` | 工具是否已执行? 空输出使用默认行为。 在云代理下，由于没有用户可以回答，`"ask"` 被视为 `"deny"`。 |                             |
| `permissionDecisionReason` | 字符串                                                        | 向代理显示的原因。 决策为 `"deny"` 时需要。 |
| `modifiedArgs`             | 对象                                                         | 要使用的替代工具参数，而不是使用原始参数。       |

当 Copilot CLI 能够显示 hook 权限提示时，用户可以在拒绝时输入可选反馈。 该反馈将追加到代理收到的消息中： `Denied by user via preToolUse hook prompt: <permissionDecisionReason>. The user provided the following feedback: <feedback>`

## `agentStop`/ `subagentStop` 决策控制

| 领域                                                                                       | 价值观 | Description                   |
| ---------------------------------------------------------------------------------------- | --- | ----------------------------- |
| `decision`                                                                               |     |                               |
| `"block"`、`"allow"`                                                                      |     |                               |
| `"block"` 强制另一个代理回合将 `reason` 用作提示。                                                      |     |                               |
| `reason`                                                                                 | 字符串 | 当`decision`是`"block"`时，提示下一轮。 |
| `modifiedResponse`                                                                       | 字符串 |                               |
| \*\*                                                                                     |     |                               |
| `subagentStop` 仅限于此。\*\* 替换在允许子代理完成时返回给父代理的响应，这对于对子代理输出进行删改或重新格式化非常有用。 不适用于 `agentStop`。 |     |                               |

`decision` 和 `reason` 对于 `agentStop` 和 `subagentStop` 两者的表现相同。
`modifiedResponse` 仅适用于 `subagentStop`：

* 有效的 `block` 决定优先于 `modifiedResponse`：如果某个钩子同时返回两者，子代理将继续执行，而重写会被丢弃。
* 重写不会在多个匹配的钩子之间组合生效。 每个钩子都会接收同一个原始 `response`，而最后一个返回 `modifiedResponse` 的钩子会生效——将脱敏器和格式化器串联使用，并不会把脱敏后的文本传给格式化器。
* camelCase 和 `decision` 兼容配置的输出字段名称（`reason`、`modifiedResponse`、VS Code）是相同的。

> \[!NOTE]
> **失控的后卫。** 在连续 8 次 `block` 继续后，CLI 会绕过该钩子并仍然结束当前轮次，以避免出现无限循环。 使用 `stop_hook_active` 上的 `agentStop` 输入字段来检测当前轮次是否已被迫继续，并在触及上限前自行限制。

## `postToolUse` 输出

挂钩 `postToolUse` 可以通过将 JSON 对象写入 stdout 来修改工具结果或为模型注入其他上下文。

```typescript
{
    modifiedResult?: {
        resultType: "success";
        textResultForLlm: string;
    };
    additionalContext?: string;
}
```

| 领域                  | 类型  | Description                                                                                                   |
| ------------------- | --- | ------------------------------------------------------------------------------------------------------------- |
| `modifiedResult`    | 对象  | 替换工具的结果。 必须具有 `resultType: "success"`。 如果返回了 `resultType: "failure"`，则故障会向下游传递，接下来会触发 `postToolUseFailure`。   |
| `additionalContext` | 字符串 | 在 `textResultForLlm` 后附加额外指导，以便模型在同一轮次中看到它，且位于工具输出之后。 当多个钩子返回 `additionalContext` 时，结果会用两个换行符连接，总长度上限为 10 KB。 |

返回 `{}` 或清空输出以保留原始成功结果。

> \[!NOTE]
> `modifiedResult` 同时被 SDK 编程挂钩和命令/HTTP 配置文件 `postToolUse` 挂钩支持。

**匹配器：** 可选正则表达式针对 `toolName` 进行测试。 正则表达式模式是字段的值 `matcher` ，编译为 `^(?:PATTERN)$`，并且必须与整个工具名称匹配。 如果模式不是有效的正则表达式，则跳过挂钩。 省略 `matcher` 以接收来自所有工具的结果。

```json
{
    "type": "command",
    "matcher": "bash|edit",
    "bash": "./scripts/log-tool.sh"
}
```

## `permissionRequest` 决策控制

> \[!NOTE]
> **Copilot CLI 仅限于此。** `permissionRequest`挂钩不适用于Copilot cloud agent，工具调用已获得预先批准（请参阅云代理执行环境表中**交互**行）。 使用`preToolUse`在云代理中进行权限决策。

该 `permissionRequest` 挂钩在权限服务运行前触发—在规则检查、会话审批、自动允许/自动拒绝和用户提示之前触发。 如果挂钩返回 `behavior: "allow"` 或 `"deny"`，该决策会使正常权限流短路。 不返回任何结果时，会回退到正常权限处理。 使用它以编程方式批准或拒绝工具调用-特别适用于 CLI 管道模式（`-p`）和其他 CLI CI 用法，其中没有交互式提示可用。 它不适用于云代理。

所有已配置的 `permissionRequest` 挂钩均为每个请求运行（`read` 和 `hook` 权限类型除外，这两类在挂钩运行前短路）。 挂钩输出将合并，且后面的挂钩输出会覆盖前面的输出。

**沙盒绕过例外：** 对于任何请求逃离沙盒（`requestSandboxBypass: true` in `toolInput`）的请求，钩子 `allow` 都不会预先批准该请求，也不会绕过用户提示——离开沙盒属于权限提升操作，必须始终由用户以交互方式交互确认。 这涵盖一个请求在沙盒外运行的 shell 命令，以及其 URL 被沙盒网络策略拒绝的 `web_fetch`。 仅 `deny` 会继续向上传递（因此策略钩子可以阻止逃逸）；`allow`（或未作出决定）则转入正常提示。

**匹配器：** 可选正则表达式针对 `toolName` 进行测试。 正则表达式模式是 `matcher` 字段的值，锚定为 `^(?:PATTERN)$`，并且必须匹配完整的工具名称。 设置后，挂钩仅针对匹配的工具名称触发。

> \[!NOTE]
> **Claude 格式匹配器（PascalCase `PermissionRequest`）：** 使用 PascalCase 事件名称 `PermissionRequest` 配置的钩子使用与 `PreToolUse` 相同的 Claude 匹配器语义。 有关匹配程序规则和工具名称表，请参阅 [Claude 格式匹配程序（PascalCase PreToolUse](#claude-format-matchers-pascalcase-pretooluse) ）。

将 JSON 输出到 stdout 以控制权限决策：

| 领域                 | 价值观            | Description                      |
| ------------------ | -------------- | -------------------------------- |
| `behavior`         |                |                                  |
| `"allow"`、`"deny"` | 是否批准或拒绝工具调用请求。 |                                  |
| `message`          | 字符串            | 拒绝时，原因会反馈给 LLM。                  |
| `interrupt`        | boolean        | 当 `true` 与 `"deny"` 结合后，会完全停止代理。 |

返回空输出或 `{}` 以进入到正常权限流。 对于命令钩子，退出代码 `2` 被视为拒绝执行，stdout JSON（如果有）与 `{"behavior":"deny"}` 合并，而 stderr 会被忽略。

## `notification` 挂钩

> \[!NOTE]
> **Copilot CLI 仅限于此。** `notification` 挂钩在 Copilot cloud agent 下不会触发。

当 `notification` CLI 发出系统通知时，挂钩会异步触发。 这些挂钩是即发即弃型挂钩：它们永远不会阻止会话，并且会记录并跳过任何错误。

**输入：**

```typescript
{
    sessionId: string;
    timestamp: number;
    cwd: string;
    hook_event_name: "Notification";
    message: string;           // Human-readable notification text
    title?: string;            // Short title (e.g., "Permission needed", "Shell completed")
    notification_type: string; // One of the types listed below
}
```

**通知类型：**

| 类型                         | 当它触发时                                 |
| -------------------------- | ------------------------------------- |
| `shell_completed`          | 后台（异步）shell 命令完成                      |
| `shell_detached_completed` | 断开连接的 shell 会话完成                      |
| `agent_completed`          | 后台子智能体完成（已完成或失败）                      |
| `agent_idle`               | 后台代理完成一个轮次并进入空闲状态（正在等待 `write_agent`） |
| `permission_prompt`        | 代理请求执行工具的权限                           |
| `elicitation_dialog`       | 代理从用户请求其他信息                           |

**Output:**

```typescript
{
    additionalContext?: string; // Injected into the session as a user message
}
```

如果 `additionalContext` 返回，文本将作为追加的用户消息注入到会话中。 如果会话处于空闲状态，可能会触发进一步的代理处理。 返回 `{}` 或空输出以不执行任何操作。

**匹配器：** 在 `notification_type` 上可选的正则表达式。 正则表达式模式是 `matcher` 字段的值，并锚定为 `^(?:PATTERN)$`。 省略 `matcher` 以接收所有通知类型。

## 匹配器筛选

多个事件允许在每个挂钩条目中使用可选的 `matcher` 正则表达式，用于过滤挂钩将触发的调用。 它被编译为 `^(?:PATTERN)$`，并且必须与完整值匹配。 无效的正则表达式将导致跳过该挂钩条目。

\| 事件 |
`matcher` 匹配 |
\|-------|------------------------------|
\| `notification` | `notification_type` |
\| `permissionRequest` | `toolName` |
\| `postToolUse` | `toolName` |
\| `preCompact` |
`trigger`（`"manual"` 或 `"auto"`） |
\| `preToolUse` | `toolName` |
\| `subagentStart` | `agentName` |

## 挂钩匹配工具名称

| 工具名称         | Description                                      |
| ------------ | ------------------------------------------------ |
| `ask_user`   | 询问用户一个澄清的问题。 在云代理下，没有用户，因此 `ask_user` 不会产生有用的结果。 |
| `bash`       | 执行 shell 命令（Unix）。                               |
| `create`     | 创建新文件。                                           |
| `edit`       | 修改文件内容。                                          |
| `glob`       | 按模式查找文件。                                         |
| `grep`       | 搜索文件内容。                                          |
| `powershell` | 执行 shell 命令（Windows）。 不会显示在云代理（Linux 沙盒）下。       |
| `task`       | 运行子代理任务。                                         |
| `view`       | 读取文件内容。                                          |
| `web_fetch`  | 抓取网页。                                            |

如果配置了同一类型的多个挂钩，则它们按顺序执行。 对于 `preToolUse`，如果有挂钩返回 `"deny"`，则该工具会被阻止。 对于大多数事件，钩子失败（除 `2` 外的非零退出代码，或超时）会被记录并跳过。
**例外：`preToolUse`命令钩子在退出 `2` 以及发生非超时错误时都将采用失败即关闭的方式**——退出 `2`、崩溃或任何其他非零退出（超时除外）都会拒绝此次工具调用，即使该钩子的 stdout JSON 报告为 `permissionDecision: "allow"`。
**超时始终按故障开放处理，包括对于 `preToolUse` 和由管理员部署的策略钩子**：系统会显示警告，并且工具调用会继续按正常的权限流程执行，而不是被拒绝。

## 命令挂钩的退出代码

| 退出代码                                                                                                                                                                                                                                    | Meaning                         |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| `0`                                                                                                                                                                                                                                     | 成功。                             |
| `stdout` 如果存在，则分析为挂钩输出 JSON。                                                                                                                                                                                                            |                                 |
| `2`                                                                                                                                                                                                                                     | 默认情况下被视为警告。                     |
| `stderr` 会显示给用户，但运行会继续。 对于 `permissionRequest` 和 `preToolUse`，退出 `2` 被视为拒绝：任何 `stdout` JSON 都与拒绝决策合并，即使该 JSON 报告 `permissionDecision: "allow"`，工具调用也会被拒绝。 对于`postToolUseFailure`，退出`2`被视为`additionalContext`，并且`stdout`被追加到展示给代理的失败信息中。 |                                 |
| 其他非零                                                                                                                                                                                                                                    | 记录为挂钩失败。 运行继续 (fail-open)。      |
| **例外：`preToolUse` 是故障关闭的** — 非零退出（除退出码 2 外）会以 `"Denied by preToolUse hook (hook errored)"` 拒绝工具调用。                                                                                                                                      |                                 |
| Timeout                                                                                                                                                                                                                                 | 在 `timeoutSec` 后被终止。 记录错误，继续执行。 |
| **对于所有事件（包括 `preToolUse` 和管理员部署的策略挂钩），超时都会按故障开放处理**——系统会显示警告，处理将继续进行，如同该挂钩未曾运行。 对于 `preToolUse`，工具调用通过正常权限流进行，而不是被拒绝。 已崩溃或显式拒绝的钩子仍按故障封闭方式处理；只有超时情况例外。                                                                                   |                                 |

对于大多数事件，非零退出和超时会被记录并跳过 — 智能体执行将继续。 对于 `preToolUse` 命令钩子，退出码 2、崩溃以及其他非零退出都会按故障关闭方式处理，并拒绝工具调用——退出码 2 一律拒绝，即使该钩子的 `stdout` JSON 报告 `permissionDecision: "allow"` 也是如此——但 **超时始终按故障开放方式处理**——缓慢或无法访问的钩子不得在无提示的情况下阻止工具调用或操作执行，即使该钩子是管理员作为策略部署的。

## 禁用所有挂钩

当您想在磁盘上保留挂钩配置但阻止其运行时，使用 `disableAllHooks`。例如：

* 在调试问题时，您希望确认挂钩是原因，但又不希望删除配置。
* 在敏感任务（代码审查、发布分支、处理密钥）期间暂停自动化，同时保留配置。 （仅限 **Copilot CLI。**）
* 将挂钩文件放入源代码控制中，参与者可通过在 `settings.json` 存储库中设置选项在本地选择不使用。 （仅限 **Copilot CLI。**）
* 在交互式会话期间暂时禁用运行缓慢或输出冗余的挂钩。 （仅限 **Copilot CLI。**）

在顶级设置 `disableAllHooks` 为 `true` 以跳过文件中的所有挂钩，同时不删除该文件。

```json
{
  "version": 1,
  "disableAllHooks": false,
  "hooks": {
    "preToolUse": [ /* hook entries */ ]
  }
}
```

行为取决于设置标志的位置：

* **在单个 `.github/hooks/*.json` 文件** 内 — 仅跳过该文件中声明的挂钩。
  Copilot CLI 和 Copilot cloud agent 均支持此设置。
* \*\* 在 `settings.json` 存储库的顶层 \*\* — 仅限 **Copilot CLI。** 该存储库中的所有会话都会跳过来自所有来源（存储库文件、用户文件、插件和内联挂钩块）的每个挂钩。 策略钩子不受影响，并继续运行。 云代理不会加载 `settings.json`。

## 延伸阅读

* [与 GitHub Copilot CLI 一起使用挂钩](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-cli/customize-copilot/use-hooks)
* [GitHub Copilot 挂钩参考](/zh/enterprise-cloud@latest/copilot/reference/hooks-reference)
* [GitHub Copilot CLI 命令参考](/zh/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference)
* [GitHub Copilot 云代理概念](/zh/enterprise-cloud@latest/copilot/concepts/agents/cloud-agent)