Visual Studio Code (Preview) 中的代理钩子
钩子使你能够在代理会话的关键生命周期点执行自定义壳命令。使用钩子自动化工作流程、执行安全策略、验证作并与外部工具集成。钩子以确定性方式运行,可以控制代理行为,包括阻止工具执行或向对话注入上下文。
代理钩子目前处于VS Code 1.109.3的预览阶段。配置格式和行为可能会在未来的版本中发生变化。
你的组织可能禁用了 VS Code 中的钩子。如需更多信息,请联系您的管理层。详情请参见企业政策。
钩子设计为跨代理类型工作,包括本地代理、后台代理和云代理。每个钩子接收结构化的JSON输入,并可返回JSON输出以影响代理行为。
为什么要用挂钩?
钩子提供确定性、代码驱动的自动化。与指导代理行为的指令或自定义提示不同,钩子在特定生命周期点执行代码,并保证结果:
-
执行安全策略:屏蔽像这样的危险命令
RM -RF或掉落表无论特工如何被提示,都必须执行。 -
自动化代码质量:文件修改后自动运行格式化器、打印器或测试。
-
建立审计轨迹:记录每一次工具调用、命令执行或文件变更,以便合规和调试。
-
注入上下文:添加项目特定信息、API密钥或环境细节,帮助代理做出更好的决策。
-
控制批准:自动批准安全作,敏感作需确认。
钩子生命周期事件
VS Code 支持八个在代理会话中特定时刻触发的钩子事件:
| 钩子事件 | 当它开火 | 常见用例 |
|---|---|---|
SessionStart |
用户提交新会话的第一个提示 | 初始化资源,记录会话开始,验证项目状态 |
用户提示提交 |
用户提交提示 | 审计用户请求,注入系统上下文 |
工具使用前 |
在代理调用任何工具之前 | 阻止危险作,要求审批,修改工具输入 |
工具使用后 |
工具成功完成后 | 运行格式化工具,记录结果,触发后续作 |
预紧凑型 |
在对话上下文被压缩之前 | 导出重要上下文,在截断前保存状态 |
SubagentStart |
Subagent 被生成 | 跟踪嵌套代理使用情况,初始化子代理资源 |
SubagentStop(子代理停止) |
子代理完成 | 综合结果,清理分剂资源 |
停下 |
代理会话结束 | 生成报告、清理资源、发送通知 |
配置钩子
钩子配置在存储在工作区或用户目录中的 JSON 文件中。
钩子文件位置
VS Code 在以下位置搜索钩子配置文件:
- 工作空间:
.github/hooks/*.json- 与团队共享的项目特定钩子 - 工作空间:
.claude/settings.local.json- 本地工作区钩子(未提交) - 工作空间:
.claude/settings.json- 工作区级钩子 - 用户:
~/.Claude/settings.json- 应用于所有工作区的个人钩子
对于同一事件类型,Workspace 钩子优先于用户钩子。
钩子配置格式
创建一个带有钩子包含每种事件类型的钩子命令数组的对象。VS Code 使用与 Claude Code 和 Copilot CLI 相同的钩子格式以保证兼容性:
{
"hooks": {
"PreToolUse": [
{
"type": "command",
"command": "./scripts/validate-tool.sh",
"timeout": 15
}
],
"PostToolUse": [
{
"type": "command",
"command": "npx prettier --write \"$TOOL_INPUT_FILE_PATH\""
}
]
}
}
钩子命令属性
每个钩子条目必须类型:“命令”以及至少一个命令属性:
| 财产 | 类型 | 描述 |
|---|---|---|
类型 |
弦 | 一定是“指挥” |
指挥 |
弦 | 默认运行命令(跨平台) |
窗户 |
弦 | Windows 专用命令覆盖 |
Linux |
弦 | Linux 专用命令覆盖 |
OSX |
弦 | macOS 专用命令覆盖 |
慢性消耗病 |
弦 | 工作目录(相对于仓库根目录) |
环境 |
对象 | 额外环境变量 |
暂停 |
人数 | 超时时间为秒(默认:30秒) |
作系统专用命令是根据扩展主机平台选择的。在远程开发场景(SSH、容器、WSL)中,这可能与本地作系统不同。
作系统专用命令
为每个作系统指定不同的命令:
{
"hooks": {
"PostToolUse": [
{
"type": "command",
"command": "./scripts/format.sh",
"windows": "powershell -File scripts\\format.ps1",
"linux": "./scripts/format-linux.sh",
"osx": "./scripts/format-mac.sh"
}
]
}
}
执行服务会根据你的作系统选择合适的命令。如果没有定义作系统特定的命令,则会退回到指挥财产。
钩子输入与输出
钩子通过 STDIN(输入)和 stdout(输出)使用 JSON 与 VS Code 通信。
常见输入字段
每个钩子通过 stdin 接收一个 JSON 对象,这些字段共有:
{
"timestamp": "2026-02-09T10:30:00.000Z",
"cwd": "/path/to/workspace",
"sessionId": "session-identifier",
"hookEventName": "PreToolUse",
"transcript_path": "/path/to/transcript.json"
}
通用输出格式
钩子可以通过标准输出返回JSON,以影响代理行为。所有钩子都支持以下输出字段:
{
"continue": true,
"stopReason": "Security policy violation",
"systemMessage": "Operation blocked by security hook"
}
| 场地 | 类型 | 描述 |
|---|---|---|
继续 |
布尔值 | 设置为错误停止处理(默认:确实如此) |
停止理性 |
弦 | 停止的原因(向模型展示) |
systemMessage |
弦 | 向用户显示的消息 |
出口代码
钩子的退出代码决定了 VS Code 如何处理该结果:
| 出口代码 | 行为 |
|---|---|
0 |
Success: parse stdout as JSON |
2 |
阻断误差:停止处理并向模型显示误差 |
| 其他 | 非阻塞警告:向用户显示警告,继续处理 |
工具使用前
该工具使用前钩子在特工召唤工具前开火。
PreToolUse 输入
除了公共领域之外,工具使用前钩子接收:
{
"tool_name": "editFiles",
"tool_input": { "files": ["src/main.ts"] },
"tool_use_id": "tool-123"
}
PreToolUse 输出
该工具使用前钩子可以通过hookParticularOutput主题:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by policy",
"updatedInput": { "files": ["src/safe.ts"] },
"additionalContext": "User has read-only access to production files"
}
}
| 场地 | 价值观 | 描述 |
|---|---|---|
许可决定 |
“允许”,“否认”,“问” |
控制工具审批 |
许可决定理由 |
弦 | 原因显示给用户 |
更新输入 |
对象 | 修改工具输入(可选) |
附加背景 |
弦 | 模型的额外背景 |
权限决策优先级:当多个钩子针对同一工具调用运行时,限制最严格的决策获胜:
否认(最严格):块工具执行问问: 需要用户确认允许(限制最少):自动批准执行
更新输入节目形式: 以确定 的格式更新输入,运行命令“显示聊天调试视图”,找到已记录的工具模式。如果更新输入如果不符合预期的模式,就会被忽略。
工具使用后
该工具使用后钩子在工具成功完成后发射。
PostToolUse 输入
除了公共领域之外,工具使用后钩子接收:
{
"tool_name": "editFiles",
"tool_input": { "files": ["src/main.ts"] },
"tool_use_id": "tool-123",
"tool_response": "File edited successfully"
}
PostToolUse 输出
该工具使用后钩子可以为模型提供额外的上下文,或阻止进一步处理:
{
"decision": "block",
"reason": "Post-processing validation failed",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "The edited file has lint errors that need to be fixed"
}
}
| 场地 | 价值观 | 描述 |
|---|---|---|
判决 |
“阻挡” |
块后续处理(可选) |
原因 |
弦 | 阻挡原因(向模型展示) |
hookSpecificOutput.additionalContext |
弦 | 在对话中加入了额外的背景 |
用户提示提交
该用户提示提交当用户提交提示时,钩子会触发。
用户提示提交输入
除了公共领域之外,用户提示提交钩子获得提示字段中显示用户提交的文本。
该用户提示提交Hook 仅使用通用输出格式。
SessionStart
该SessionStart当新的代理会话开始时,钩子会触发。
SessionStart 输入
除了公共领域之外,SessionStart钩子接收:
{
"source": "new"
}
| 场地 | 类型 | 描述 |
|---|---|---|
资料来源 |
弦 | 会议是如何开始的。目前一直如此“新”. |
SessionStart 输出
该SessionStarthook 可以为代理的对话注入额外的上下文:
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Project: my-app v2.1.0 | Branch: main | Node: v20.11.0"
}
}
| 场地 | 类型 | 描述 |
|---|---|---|
附加背景 |
弦 | 补充了对特工对话的背景 |
停下
该停下Hook 在特工会话结束时触发。
停止输入
除了公共领域之外,停下钩子接收:
{
"stop_hook_active": false
}
| 场地 | 类型 | 描述 |
|---|---|---|
stop_hook_active |
布尔值 | 确实如此当代理因之前的停钩而继续时。检查该值以防止代理无限运行。 |
停止输出
该停下钩子可以防止代理人停止:
{
"hookSpecificOutput": {
"hookEventName": "Stop",
"decision": "block",
"reason": "Run the test suite before finishing"
}
}
| 场地 | 价值观 | 描述 |
|---|---|---|
判决 |
“阻挡” |
防止代理人停止 |
原因 |
弦 | 决策时要求“阻挡”.告诉代理为什么应该继续。 |
当停下hook 阻止代理停止,代理继续运行,额外回合消耗高级请求。一定要检查stop_hook_active阻止代理无限期运行。
SubagentStart
该SubagentStart钩子在生成子代理人时触发。
SubagentStart 输入
除了公共领域之外,SubagentStart钩子接收:
{
"agent_id": "subagent-456",
"agent_type": "Plan"
}
| 场地 | 类型 | 描述 |
|---|---|---|
agent_id |
弦 | 子代理的唯一标识符 |
agent_type |
弦 | 代理名称(例如,“计划”用于内置代理或自定义代理名称) |
SubagentStart 输出
该SubagentStarthook 可以为子代理的对话注入额外的上下文:
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "This subagent should follow the project coding guidelines"
}
}
| 场地 | 类型 | 描述 |
|---|---|---|
附加背景 |
弦 | 补充了副代理人对话的背景 |
SubagentStop(子代理停止)
该SubagentStop(子代理停止)当子代理完成时,钩子触发。
SubagentStop 输入
除了公共领域之外,SubagentStop(子代理停止)钩子接收:
{
"agent_id": "subagent-456",
"agent_type": "Plan",
"stop_hook_active": false
}
| 场地 | 类型 | 描述 |
|---|---|---|
agent_id |
弦 | 子代理的唯一标识符 |
agent_type |
弦 | 代理名称(例如,“计划”用于内置代理或自定义代理名称) |
stop_hook_active |
布尔值 | 确实如此当子代理因之前的停止钩而继续时。检查该值以防止子代理无限运行。 |
SubagentStop 输出
该SubagentStop(子代理停止)钩子可以防止子代理停止:
{
"decision": "block",
"reason": "Verify subagent results before completing"
}
| 场地 | 价值观 | 描述 |
|---|---|---|
判决 |
“阻挡” |
防止亚剂停止使用 |
原因 |
弦 | 决策时要求“阻挡”.告诉分代理为什么应该继续。 |
预紧凑型
该预紧凑型钩子在对话上下文被压缩之前就开始了。
预紧输入
除了公共领域之外,预紧凑型钩子接收:
{
"trigger": "auto"
}
| 场地 | 类型 | 描述 |
|---|---|---|
触发点 |
弦 | 压实是如何触发的。“自动”当对话时间过长,预算有限时。 |
该预紧凑型Hook 仅使用通用输出格式。
用 /hooks 命令配置 hooks
使用该/钩子在聊天中使用斜杠命令通过交互式界面配置钩子:
-
类型
/钩子在聊天输入中按下回车键。 -
从列表中选择一个钩子事件类型。
-
选择一个现有的钩子进行编辑,或选择“添加新钩子”来创建一个。
-
选择或创建一个挂钩配置文件。
命令会在编辑器中打开钩子文件,光标位于命令字段,准备编辑。
使用场景
以下示例展示了常见的钩子模式。
阻止危险终端命令
创建一个工具使用前防止破坏性命令的挂钩:
.github/hooks/security.json:
{
"hooks": {
"PreToolUse": [
{
"type": "command",
"command": "./scripts/block-dangerous.sh",
"timeoutSec": 5
}
]
}
}
剧本/block-dangerous.sh:
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
TOOL_INPUT=$(echo "$INPUT" | jq -r '.tool_input')
if [ "$TOOL_NAME" = "runTerminalCommand" ]; then
COMMAND=$(echo "$TOOL_INPUT" | jq -r '.command // empty')
if echo "$COMMAND" | grep -qE '(rm\s+-rf|DROP\s+TABLE|DELETE\s+FROM)'; then
echo '{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"Destructive command blocked by security policy"}}'
exit 0
fi
fi
echo '{"continue":true}'
编辑后自动格式化代码
修改任何文件后自动运行 Prettier:
.github/hooks/formatting.json:
{
"hooks": {
"PostToolUse": [
{
"type": "command",
"command": "./scripts/format-changed-files.sh",
"windows": "powershell -File scripts\\format-changed-files.ps1",
"timeout": 30
}
]
}
}
剧本/format-changed-files.sh:
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
if [ "$TOOL_NAME" = "editFiles" ] || [ "$TOOL_NAME" = "createFile" ]; then
FILES=$(echo "$INPUT" | jq -r '.tool_input.files[]? // .tool_input.path // empty')
for FILE in $FILES; do
if [ -f "$FILE" ]; then
npx prettier --write "$FILE" 2>/dev/null
fi
done
fi
echo '{"continue":true}'
日志工具在审计中的应用
创建所有工具调用的审计跟踪:
.github/hooks/audit.json:
{
"hooks": {
"PreToolUse": [
{
"type": "command",
"command": "./scripts/log-tool-use.sh",
"env": {
"AUDIT_LOG": ".github/hooks/audit.log"
}
}
]
}
}
剧本/log-tool-use.sh:
#!/bin/bash
INPUT=$(cat)
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
SESSION_ID=$(echo "$INPUT" | jq -r '.sessionId')
echo "[$TIMESTAMP] Session: $SESSION_ID, Tool: $TOOL_NAME" >> "${AUDIT_LOG:-audit.log}"
echo '{"continue":true}'
特定工具需要批准
强制手动确认修改基础设施的工具:
.github/hooks/approval.json:
{
"hooks": {
"PreToolUse": [
{
"type": "command",
"command": "./scripts/require-approval.sh"
}
]
}
}
剧本/require-approval.sh:
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
# Tools that should always require approval
SENSITIVE_TOOLS="runTerminalCommand|deleteFile|pushToGitHub"
if echo "$TOOL_NAME" | grep -qE "^($SENSITIVE_TOOLS)$"; then
echo '{"hookSpecificOutput":{"permissionDecision":"ask","permissionDecisionReason":"This operation requires manual approval"}}'
else
echo '{"hookSpecificOutput":{"permissionDecision":"allow"}}'
fi
在会话开始时注入项目上下文
会议开始时提供项目具体信息:
.github/hooks/context.json:
{
"hooks": {
"SessionStart": [
{
"type": "command",
"command": "./scripts/inject-context.sh"
}
]
}
}
脚本/inject-context.sh:
#!/bin/bash
PROJECT_INFO=$(cat package.json 2>/dev/null | jq -r '.name + " v" + .version' || echo "Unknown project")
BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
cat <<EOF
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Project: $PROJECT_INFO | Branch: $BRANCH | Node: $(node -v 2>/dev/null || echo 'not installed')"
}
}
EOF
安全
如果代理能够访问通过钩子运行的编辑脚本,那么它就有能力在自身运行时修改这些脚本,并执行它写的代码。我们建议使用chat.tools.edits.autoApprove禁止代理未经人工批准编辑钩子脚本。
故障排除
查看钩子诊断
要查看哪些钩子被加载并检查配置错误:
-
在聊天视图中右键点击,选择诊断。
-
找“钩子”部分,查看加载钩子和任何验证错误。
视图钩子输出
回顾钩子输出和错误:
-
打开输出面板。
-
从频道列表中选择GitHub Copilot聊天钩子。
常见问题
钩子未执行:确认钩子文件是否在.github/hooks/并且有.json延伸。检查一下类型属性设置为“指挥”.
权限拒绝错误:确保你的钩子脚本具有执行权限(chmod +x script.sh).
超时错误:增加暂停重视或优化你的钩子脚本。默认是30秒。
JSON 解析错误:验证你的钩子脚本输出的 JSON 是有效的。用途JQ或者用 JSON 库来构建输出。
常见问题解答
VS Code 是如何处理 Claude Code 钩子配置的?
VS Code 解析 Claude Code 的钩子配置格式,包括匹配器语法。目前,VS Code 忽略匹配值,所以钩子适用于所有工具。Claude Code 使用空字符串匹配器()来表示所有工具。""
VS Code 是如何处理 Copilot CLI 钩子配置的?
VS Code 解析 Copilot CLI 钩子配置,并转换 lower CamelCase 钩子事件名称(例如工具使用前)转换为VS Code使用的PascalCase格式(工具使用前).两者兼具砰以及PowerShell支持命令格式。
安全考量
钩子执行壳级命令的权限与 VS Code 相同。仔细审查钩子配置,尤其是在使用来自不可信来源的钩子时。
-
审查钩子脚本:在启用之前检查所有钩子脚本,尤其是在共享仓库中。
-
限制钩子权限:采用最小权限原则。钩子应该只能访问他们需要的东西。
-
验证输入:钩子脚本接收来自代理的输入。验证并净化所有输入,以防止注入攻击。
-
安全凭证:切勿在钩子脚本中硬编码秘密。使用环境变量或安全的凭证存储。