前言:为什么 AI Agent 需要一个「扩展生态」

最近一两年,终端 AI 编码 Agent 逐渐成了开发者日常不可或缺的搭档。模型本身再聪明,本质上也只是一位「大脑型选手」:它必须借助工具才能真正动起手来——读取文件、执行命令、调用外部 API、操作数据库。于是你会发现一个朴素的规律:Agent 的价值上限,往往不是由模型决定的,而是由「它能触达多少工具、记住多少流程、遵守多少规则」决定的。一个只会聊天的模型和一位真正能交付代码的工程师之间的差距,恰恰就藏在这些看不见的机制里。

内置工具永远是有限的,而真实世界的需求是无限的。每个团队都有自己的缺陷跟踪系统、自己的 CI 管线、自己的数据库方言、自己的代码规范。想覆盖这些千差万别的场景,Agent 运行时就必须要能被「扩展」。目前业界扩展 Agent 主要沿着两条路径推进:一条是「协议化」,一条是「宿主化」。所谓协议化,就是定义一套开放的标准,让任何服务都能以统一的方式暴露能力给任何 Agent——MCP(Model Context Protocol,模型上下文协议)就是其中的代表,它把「如何把外部工具接入模型」这件事,从各家私有实现收敛成了公开规范,任何实现了 MCP 的服务器,理论上都能接入任何支持该协议的客户端,生态因此可以像 npm 社区一样互相复用。所谓宿主化,则是在 Agent 自身内部提供一套可插拔的机制,让你能把「做法」「流程」「规则」「自动化」沉淀下来,跟随项目或组织流动。

Grok Build(也就是 grok CLI)是 xAI 推出的终端 AI 编码 Agent。阅读它的官方文档会发现,它的扩展能力恰好被组织成了四个互相配合、分工明确的层面:MCP 服务器解决「模型手不够长」的问题——把外部服务的工具动态交给模型调用;Skills 解决「每次都要重新解释一遍流程」的问题——把可复用的操作步骤固化成提示包;Plugins 解决「如何批量打包与分发」的问题——把技能、命令、钩子、MCP 配置装进一个可安装的单元,通过类似应用商店的 marketplace 流转;Hooks 解决「如何让 Agent 守规矩、可观测」的问题——在会话生命周期关键节点上插入你自己的脚本或 HTTP 请求,实现安全拦截、审计日志与自动化。

这篇文章就是一篇「官方文档带读」。我将以 xai-org/grok-build 仓库中 user-guide 目录下的四篇官方文档为主线:07-mcp-servers.md、08-skills.md、09-plugins.md、10-hooks.md,逐篇把概念、配置、用法和边界讲清楚。所有技术细节均以官方文档为准,文中出现的配置示例与命令行,绝大多数直接取自官方文档,个别拿不准的地方我会明确标注「以当前版本官方文档为准」。Grok Build 产品迭代很快,文档中不断出现「breaking changes」之类的提醒,因此本文讨论的是写作时点的文档快照,正式上手前请以你本地安装版本的官方文档为准。读完本文,你应该能对 Grok Build 的四种扩展机制建立起一张完整的地图:知道每种机制解决什么问题、长什么样子、何时该用哪一种。

阅读提示:这是一篇教学导向的带读文章,建议配合官方文档原文一起阅读;文中的代码块均可直接复制到你的 ~/.grok/config.toml 或对应目录里实验。

你现在应该掌握了什么:扩展生态对 Agent 的意义(工具触达面决定能力上限)、MCP 协议「一次接入、处处可用」的背景,以及 Grok Build 四大扩展机制各自解决的痛点(工具、流程、分发、规则)。接下来我们从最贴近「外部世界」的 MCP 服务器讲起。

MCP 服务器接入:把外部世界的工具交给模型

在深入讲解之前,先给你一张全貌架构图,把四个机制在 Grok Build 中的位置一次性看清(依据官方文档各章节整理,非官方原图):

+-------------------------- 用户(TUI / CLI / IDE 扩展) ---------------------------+
|  斜杠命令:/commit  /hooks  /mcps  /plugins  /marketplace  /skills ...           |
+----------------------------------------+-----------------------------------------+
                                         |
                                         v
+----------------------------------------+-----------------------------------------+
|                        Grok Build 核心(grok CLI / pager)                        |
|   模型(上下文 + 系统提示)   +   内置工具(run_terminal_command、read_file ...)    |
|   内置发现/调用工具:search_tool、use_tool(面向 MCP 工具)                        |
+------+----------------+------------------+-----------------+---------------------+
       |                |                  |                 |
       v                v                  v                 v
+-------------+   +-------------+   +-------------+   +-------------+
|  MCP 服务器  |   |   Skills    |   |   Plugins   |   |    Hooks    |
| stdio / HTTP|   |  SKILL.md   |   |  打包与分发  |   |  事件钩子    |
| 外部服务工具  |   |  提示包/流程  |   |  技能+钩子+  |   | 脚本 / HTTP |
| (可发现可调用)|   | (按需激活)   |   | MCP 配置等   |   | (生命周期)  |
+-------------+   +-------------+   +-------------+   +-------------+

这张图你可以把它记成一句话:Skills 教模型「怎么做」,MCP 给模型「什么工具」,Hooks 管模型「守不守规矩」,Plugins 则负责把前三者打包起来方便分发。下面我们顺着官方文档的顺序,先看最贴近外部世界的 MCP。

什么是 MCP 服务器

MCP 服务器(MCP server)在官方文档里的定义非常朴素:它是一个「通过标准化协议把工具暴露给 Grok 的进程」。当你配置好一个 MCP 服务器后,它的工具会与 Grok 的内置工具一起出现在模型面前,模型可以在会话期间自行发现并调用这些工具。举个例子:一个 GitHub MCP 服务器可能暴露 create_issue、list_pull_requests、search_code 这类工具;一个数据库服务器可能暴露 query、list_tables、describe_schema。换句话说,你不再需要为了让模型「会查数据库」而在提示词里写满 SQL 方言——只要挂上一个 Postgres MCP 服务器,模型就能在会话里直接调用封装好的查询工具。协议细节可以参考 MCP 官方规范(modelcontextprotocol.io),Grok 侧接入时也复用了大量的生态既有实现。

值得强调的一点是:MCP 服务器里的工具与内置工具在模型眼里地位相近,但归属不同。为了避免工具重名冲突,Grok 会用服务器名做命名空间:服务器 filesystem 的工具 read_file 会变成 filesystem__read_file,服务器 github 的工具 create_issue 会变成 github__create_issue。模型侧则通过两个内置工具与它们协作:search_tool 负责在全部已启用 MCP 服务器里按名称或描述搜索可用工具;use_tool 负责真正调用某个工具(需要给出完整限定名,例如 github__create_issue)。这个「先搜索、再调用」的两段式设计,让模型面对成百上千个外部工具时不会迷失。

stdio 与 HTTP/SSE:两种运输方式

MCP 服务器接入方式主要分两类,官方文档里给出了清晰的配置范式,全部写在 ~/.grok/config.toml(用户级)的 [mcp_servers.<name>] 小节下:

第一种是 stdio(本地进程)模式:Grok 直接拉起一个本地进程,通过标准输入输出与它通信。它适合必须跑在本地的工具——文件系统访问、本地数据库、自建内部服务。配置长这样(字段注释是官方文档原意):

[mcp_servers.my-server]
command = "/path/to/server"           # 服务器可执行文件
args = ["--flag", "value"]            # 命令行参数
env = { API_KEY = "sk-..." }          # 注入的环境变量
enabled = true                        # 是否启用(默认 true)
startup_timeout_sec = 30              # 启动超时,秒(默认 30)
tool_timeout_sec = 6000               # 单次工具调用兜底超时,秒(默认 6000)
tool_timeouts = { slow_op = 120 }     # 按工具名覆盖超时,秒

这里有几个值得注意的细节。第一,很多 stdio 服务器是 npx/uvx 包装的,首次启动要现场下载包,冷启动很慢,默认 30 秒的启动超时可能不够用。除了逐服务器调大 startup_timeout_sec,官方还提供了两个全局开关:环境变量 MCP_TIMEOUT(毫秒,与 Claude Code 兼容)或 GROK_MCP_STARTUP_TIMEOUT_SECS(秒);当然,某个服务器自己的 startup_timeout_sec 优先级最高。第二,MCP 工具返回结果过大会把会话撑爆,官方给了一个默认 20000 字节的截断阈值(超出部分会整体倾倒进会话目录下的 mcp/ 文件夹备查),你可以用环境变量 GROK_MAX_MCP_OUTPUT_BYTES 或在配置里设 [mcp] max_output_bytes 调大调小,其优先级顺序是:requirements.toml > 环境变量 > 仓库级 .grok/config.toml > 用户级配置 > 默认值。

第二种是 HTTP/SSE(远程服务器)模式:服务器部署在远端,Grok 直接通过 URL 访问。如今主流 SaaS 的 MCP 端点基本都是这个形态,配置最简:

[mcp_servers.remote-api]
url = "https://mcp.example.com/api"
headers = { "Authorization" = "Bearer token" }

若服务器支持 streamable HTTP 并依赖会话 ID 保持状态,官方还给出了带 x-mcp-session-id 头的示例,值为 {{session_id}} 占位符,由 Grok 运行时展开。文档特别提醒:MCP 数据面请求(JSON-RPC 与 SSE)默认带 User-Agent: grok-cli/<version> 头,OAuth 相关流程则由 rmcp OAuth 客户端自己处理;如果你在配置里写了一个非法格式的 User-Agent,它会被头解析丢弃并告警,服务器最终仍会收到默认 UA。另外,凡是能在远端直接提供原生 HTTP/SSE 端点的服务器,官方都建议直接用 url 形式,而不是套一层 npx mcp-remote <url> 的 stdio 代理——原生形式免去了每个会话多起一个子进程的开销,还能让 Grok 用自己的 OAuth 客户端向服务商注册。

作用域与优先级:全局、仓库、还是当前目录

MCP 服务器可以按需挂在三个层级:~/.grok/config.toml 对所有项目生效(优先级最低);仓库根目录的 .grok/config.toml 对当前仓库生效(优先级居中);当前工作目录的 .grok/config.toml 优先级最高。Grok 会从当前目录一路向上走到 git 仓库根,逐层加载沿途的 .grok/config.toml。如果项目里定义了一个与全局同名的服务器,项目版本会整个替换掉全局版本——注意是「替换」而不是「字段合并」,别指望两边配置能互补。下表是官方文档的原表:

配置位置 作用域 优先级
~/.grok/config.toml 所有项目 最低
<repo根>/.grok/config.toml 当前仓库 中等
<当前目录>/.grok/config.toml 当前目录 最高

把 MCP 配置提交进仓库还有一个额外的好处:整个团队 clone 下来就能用同一套工具。不过文档提醒,项目级配置只认 [mcp_servers]、[plugins]、[permission] 这几个小节,其余配置段仍然只从 ~/.grok/config.toml 读取。为了兼容,Grok 还会按优先级合并多种来源:config.toml > Claude 的 .claude.json > Cursor 的 .cursor/mcp.json > MCP 标准的 .mcp.json,冲突时高优先级来源胜出;不想要某个来源,可以在 [compat.<vendor>] 里关掉扫描,或用 grok inspect 查看每个服务器到底来自哪里(输出里会标注 [cursor]、[claude] 之类的来源)。

命令行管理:一行一个服务器

官方文档非常强调「不用手改配置文件」的体验,为此 grok 提供了一整套 MCP 管理命令:

# 列出已配置的服务器(--json 输出机器可读格式)
grok mcp list

# 添加 stdio 服务器:-- 之后的部分原样传给服务器命令,-y 不会被 grok 截胡
grok mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /path/to/dir

# 添加带环境变量的 stdio 服务器(-e 可重复)
grok mcp add postgres -e DATABASE_URL=postgres://localhost/mydb -- npx -y @modelcontextprotocol/server-postgres

# 添加远程 HTTP / SSE 服务器
grok mcp add --transport http sentry https://mcp.sentry.dev/mcp
grok mcp add --transport sse linear https://mcp.linear.app/sse

# 移除 / 启用 / 停用
grok mcp remove github
grok mcp enable github
grok mcp disable github

# 体检:检查某个(或全部)服务器的配置与连通性
grok mcp doctor

几条易踩的细节:传输方式默认是 stdio,远程服务器要显式加 --transport http 或 --transport sse;默认写入用户级配置,加 --scope project 才写入当前目录的 .grok/config.toml,方便提交共享。头部与环境变量值是「原样存储」的,所以官方强烈建议用 ${VAR} 引用环境变量,而不是把密钥直接粘进会被提交的配置文件。grok mcp list 会同时显示两个作用域的服务器,项目级的带 (project) 标记、停用的带 (disabled) 标记。另外新版有些破坏性变更值得留意:--env 现在一次只收一个 KEY=value,要写 -e A=1 -e B=2;服务器名只能由字母、数字、连字符和下划线组成。

运行时开关、OAuth 与常用示例

MCP 服务器不用重启就能启停。TUI 里敲 /mcps(或非 VS Code 系终端按 Ctrl+L 后切到 MCP Servers 标签页),就能看到每个服务器的来源、启用状态和工具数量:Space 启停、回车展开看工具清单、r 重新加载、i 给 OAuth 服务器做授权、a/x 增删。需要 OAuth 认证的服务器,Grok 会自动拉起浏览器走授权流程并把令牌存到 ~/.grok/mcp_credentials.json(Unix 上权限为 0600,仅属主可读,文档建议宿主机开启全盘加密)。托管服务直接填 url,内部服务用静态 Bearer Token 就在 headers 里写 Authorization,想避免把秘密写进文件就用 ${VAR} 展开——url、command、args、env、headers 这些字符串字段在加载时都会做环境变量展开:

# 托管的 OAuth 服务:一行一个
[mcp_servers.linear]
url = "https://mcp.linear.app/mcp"
enabled = true

# 自建服务:静态令牌走 headers,密钥用 ${VAR} 引用
[mcp_servers.internal-tools]
url = "https://mcp.internal.example.com/mcp"
enabled = true
headers = { "Authorization" = "Bearer ${INTERNAL_MCP_TOKEN}" }

# 本地 stdio:文件系统访问
[mcp_servers.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/directory"]

# 本地 stdio:PostgreSQL,带调优的超时
[mcp_servers.my-tools]
command = "/usr/local/bin/my-mcp-server"
args = ["--config", "/etc/my-mcp.json"]
startup_timeout_sec = 30
tool_timeout_sec = 120
tool_timeouts = { slow_analysis = 300, quick_lookup = 10 }

官方文档还列了一张常用服务器清单(并提醒:接入前请与各服务商确认最新端点与包名,以当前版本官方文档为准):托管型 HTTP(OAuth)的有 Linear(https://mcp.linear.app/mcp)、Sentry(https://mcp.sentry.dev/mcp)、Mixpanel(https://mcp.mixpanel.com/mcp);本地 stdio 型的有官方 @modelcontextprotocol/ 系列 npm 包:server-filesystem、server-git、server-github、server-gitlab、server-postgres、server-sqlite、server-puppeteer。更完整的社区服务器清单可以看 modelcontextprotocol/servers 仓库的 MCP Server Registry。

故障排查三板斧

MCP 接不上的时候,官方建议按这个顺序查:第一,手动跑一遍服务器命令,看它本身能不能起来(比如 npx -y @modelcontextprotocol/server-filesystem /path);第二,stdio 服务器每次启动都会把标准错误写到 ~/.grok/logs/mcp/<server>.stderr.log,握手失败先 tail 这个文件;第三,用 grok inspect 看服务器到底加载了没有、来自哪个来源,必要时开调试日志:RUST_LOG=debug GROK_LOG_FILE=/tmp/grok.log grok,然后在日志里过滤 mcp 关键字追踪启动与工具调用过程。子代理默认继承父会话已连接的 MCP 服务器,但如果子代理的工具目录是空的,按文档要检查三点:父会话是否真的连上了服务器、代理 frontmatter 的 mcpInheritance 是否被设成了 none 或过滤掉了它、插件代理自己不能声明 MCP 服务器只能看到父会话连接的。

你现在应该掌握了什么:MCP 服务器的定位(外部工具进会话的通道)、stdio 与 HTTP/SSE 两种配置形态及各自适用场景、三级作用域与多来源优先级、grok mcp 全家桶命令、命名空间与 search_tool/use_tool 的协作方式、OAuth 与密钥管理姿势,以及三板斧排查思路。

Skills 机制:把「做法」固化下来,一次编写处处复用

如果说 MCP 解决的是「工具从哪来」,Skills 解决的就是「流程从哪来」。用过一段时间 Agent 的人都有体会:很多任务你几乎每次都要花半分钟重新描述一遍——「提交代码时按 conventional commits 规范写信息」「帮我 review PR 时先看 diff 再查相关文件」…… 这类重复劳动完全可以沉淀下来。官方文档给 Skills 下的定义很精准:Skills 是可复用的提示包(reusable prompt packages),用任务专属指令扩展 Grok,让你把一套可重复的过程固化一次,而不是每个会话重新解释一遍。

概念、位置与格式约定

一个 skill 本质上就是一个目录,里面放一个 SKILL.md 文件。这个文件的 markdown 正文告诉 Grok 如何处理某一类任务:分步指令、约定、工具使用模式。官方文档特别给出了适用边界判断:当一个流程「对 AGENTS.md 来说太具体、对每次口头重述来说又太长」时,就该写成 skill;而且 Grok 只在技能确实适用于当前任务时才激活它,平时不占上下文。skill 与 slash command 的关系也很自然:每个 skill 会自动成为一个以它名字命名的斜杠命令,敲 /commit 就是把「commit」这个 skill 的指令加载进会话并让模型照着执行,后面还可以跟参数,比如 /commit fix the build。

那么 skill 文件应该放在哪里?Grok 会按优先级从多个目录发现技能,同名时高优先级位置覆盖低优先级:

位置 作用域 优先级 说明
./.grok/skills/、./.grok/commands/ 当前目录 最高 仅本目录生效;commands 下平铺的 md 是遗留斜杠命令格式
<仓库根>/.grok/skills/ 仓库 中 随版本库共享给团队
~/.grok/skills/ 用户 低 个人技能,全项目可用
~/.claude/skills/、~/.cursor/skills/ 等 用户 低 兼容 Claude Code / Cursor 生态

几个官方强调的细节:发现机制不读 .gitignore——只要文件在磁盘上就会被加载,想藏起某个技能要在配置里用 [skills] ignore,而不是靠仓库忽略规则;兼容目录默认扫描,不想要某家的可以在 [compat.<vendor>] 关掉。此外你还能用配置扩展技能目录:[skills] 小节下的 paths 追加扫描目录、ignore 彻底隐藏某些路径、disabled 让技能「留在列表里但不激活」(不进系统提示、不可被调用)。

SKILL.md 的格式是「YAML frontmatter + markdown 正文」。官方文档给了两个必填字段:name(技能标识,用小写字母、数字、连字符,最长 64 字符;空格和下划线会被归一化为连字符,省略时用目录名)和 description(技能干什么、什么时候用——Grok 靠它决定是否自动调用,省略时取正文第一段)。可选字段还包括 when-to-use(自动调用的触发短语,与 description 分开维护)、allowed-tools、argument-hint(斜杠命令自动补全提示)、user-invocable(默认 true,设 false 则从斜杠命令里隐藏)、disable-model-invocation(设为 true 后只有你手动敲斜杠命令才运行,模型不能自动调用)、model/effort(运行覆盖)、license、compatibility(环境要求)、metadata(任意键值,其中 author 和 short-description 会被提取展示)。注意多词键一律用 kebab-case,比如 when-to-use 而不是 whenToUse。

一个最小的 commit skill 长这样(官方文档原例):

---
name: commit
description: Create well-formatted git commits following conventional commit standards. Use when the user wants to commit changes or asks for /commit.
---

Review staged changes and create a commit with a clear, conventional message.

## Steps

1. Run `git diff --staged` to see changes
2. Summarize what changed and why
3. Create commit message following conventional commits format
4. Run `git commit -m "..."` with the message

如何编写一个 skill:从 /create-skill 到最佳实践

手写没问题,但官方更推荐用交互式命令 /create-skill,它会带你走完整个流程:先收集需求——询问技能名称(小写字母、数字、连字符,2–64 字符,首尾必须是字母或数字)、保存的作用域、想固化的流程描述;接着草拟 description(要写明它做什么、哪些短语能触发它、斜杠命令名是什么),你确认或修改后再继续;然后创建技能目录——在所选作用域的 .grok/skills/<name>/ 下建目录,需要时还会附带 scripts/ 或 references/ 子目录;随后写入带 frontmatter 和正文的 SKILL.md 以及配套文件;最后读回验证并告诉你怎么运行。保存位置二选一:项目级(<仓库根>/.grok/skills/<name>/,只在当前仓库生效、可随 git 共享,官方在 git 仓库内推荐这个)或用户级(~/.grok/skills/<name>/,全项目可用)。由于 Grok 会在文件变动时热重载技能,新技能几秒钟内就会出现在斜杠菜单里。

要想把技能分发给整个团队或组织,官方给出的路径是:把它打包进 plugin,再通过 marketplace 发布——这正好呼应了后面要讲的 Plugins 章节,也是 Skills 与 Plugins 两个机制衔接最紧密的地方。

关于编写质量,官方文档总结了一套最佳实践,值得逐条对照:第一,写具体的 description——它是自动调用的唯一依据,「Create git commits」太含糊,「Create well-formatted git commits following conventional commit standards. Use when the user wants to commit changes or asks for /commit.」才算合格;第二,给出具体的步骤——按顺序、可执行的程序化指令效果最好;第三,按名字引用工具——如果技能依赖 run_terminal_command、search_replace 这类具体工具,直接点名,模型才知道该用什么;第四,一个技能只做一件事——「deploy」和「rollback」拆成两个,好过一个「deploy-and-rollback」;第五,项目技能要进版本库——提交 .grok/skills/ 让全团队受益,用户级技能则保持个人私有;第六,写完先手动测——敲 /name 跑一遍确认可用,再指望自动调用。

触发、冲突与排障

技能的触发有两种途径。一是你手动敲斜杠命令(技能名即命令名,可带参数);二是模型自动调用——它会拿你的 prompt 去匹配技能的 description 和 when-to-use 字段,所以这两个字段要描述「何时该用」,例如 description 里写了 "Use when the user wants to commit changes",那么你说 "commit my changes" 就可能触发它;不想被自动触发就设 disable-model-invocation: true。名字冲突时 Grok 会「两个都保」:内置命令保留裸名(/login、/compact),技能则按作用域前缀暴露限定名——/local:commit、/repo:commit、/user:commit,插件技能是 /插件名:技能名(如 /acme:login),斜杠菜单里会用「built-in」或「skill · plugin-name」角标区分。grok inspect 能看到全部技能及其来源(project、user、bundled、config、plugin: <name> 等),还能标出冲突([collides with /login → /acme:login])和禁用状态。平台自带的 bundled 技能缓存在 ~/.grok/bundled/skills/,Grok 永远不会把它写进你的个人目录,同名的本地技能可以覆盖它,但插件技能不能覆盖原生技能、只能以限定名形式共存。

你现在应该掌握了什么:Skill 的本质(可复用提示包 = 目录 + SKILL.md)、何时该用技能(太具体不适合 AGENTS.md、太长不想每次重述)、目录与发现优先级、frontmatter 核心与可选字段、/create-skill 五步工作流、自动调用与限定名机制,以及「写具体 description、一个技能一件事、进版本库」等最佳实践。

Plugins 插件系统:把技能、工具、钩子打包成一个「安装单元」

有了 MCP 服务器、Skills、Hooks,单个开发者已经能拼出很顺手的 Agent 环境了。但这些东西都是「零件」:一个技能放在 ~/.grok/skills/,一个 MCP 配置躺在 ~/.grok/config.toml,一个钩子脚本散在 ~/.grok/hooks/。想分享给同事?逐个拷贝?想在企业里批量下发?逐个配置?Plugins 机制就是为了回答「如何批量打包与分发」而生的。官方文档的定义非常直白:一个 plugin 把技能、斜杠命令、代理(agents)、钩子和 MCP 服务器捆绑成一个可安装的单元。你从 marketplace(插件市场)获取插件、按需安装,Grok 负责加载它带来的所有东西。可以类比成手机上的应用商店:一个插件就是一个 app,marketplace 就是应用商店,一条命令装完,技能、钩子、MCP 配置一次到位。

能力边界:一个插件里能装什么

插件本质是一个目录,官方文档列出的合法组件包括:skills/ 目录里的 SKILL.md 技能、commands/ 目录里的斜杠命令、agents/ 目录里的代理、hooks/hooks.json 钩子、.mcp.json 里的 MCP 服务器配置,以及 .lsp.json 里的 LSP 服务器配置。可选的 plugin.json 清单文件可以覆盖路径或补充元数据;没有它,Grok 就按上面这些标准目录自动发现。文档举了个例子:一个 team-tools 插件可能同时捆绑部署技能、代码评审代理、pre-commit 钩子和一个 Linear MCP 服务器,团队成员一条命令全部装齐。

这里要划清一条重要的能力边界:插件分发的是 Grok 的「内容」——技能、命令、代理、钩子、MCP 配置——它不负责在你的机器上安装程序。文档专门用一节「What this does not cover」讲这件事:如果某个技能或 MCP 服务器要跑一个辅助二进制(比如自定义登录工具),那个二进制必须由你的部署渠道另行交付。同理,技能旁边可以带辅助脚本(比如它调用的 Python 文件),脚本会随插件一起拷贝到机器上,但脚本的运行环境和它 import 的第三方包必须本来就在——插件只送文件,不送运行时。另外,插件里的技能也可以声明自己的钩子吗?不可以:插件代理(plugin-name:agent-name)的 frontmatter 不能声明自己的 mcpServers 或 hooks,也不能设 permissionMode: bypassPermissions,它们默认继承父会话连接的 MCP 服务器——这是文档明确写出的安全限制。

获取与加载:marketplace、安装、启用、信任

使用插件市场是两步走,像添加应用商店一样:先添加 marketplace 源(此时什么都没安装,只是让 Grok 能浏览它的目录),再逐个安装想要的插件。源可以是 GitHub 仓库(owner/repo 简写)、任意 git 主机的完整 URL,或本地文件夹。命令行操作如下:

# 添加 marketplace 源:GitHub 简写 / git URL / 本地目录
grok plugin marketplace add my-org/team-plugins
grok plugin marketplace add https://gitlab.com/acme/plugins.git
grok plugin marketplace add ./my-marketplace

# 浏览与管理源
grok plugin marketplace list
grok plugin marketplace update [<name>]
grok plugin marketplace remove <url>

# 安装插件:--trust 表示信任(代码类组件才会真正激活)
grok plugin install deploy-tools --trust

# 管理已安装的插件
grok plugin list
grok plugin uninstall <name> [--confirm] [--keep-data]
grok plugin update [<name>]            # 不写名字 = 全部更新
grok plugin enable <name>
grok plugin disable <name>
grok plugin details <name>             # 查看插件包含哪些组件

安装源支持 owner/repo、owner/repo@v1.0(某个 ref)、owner/repo@<commit-sha>(精确提交,拉取后校验)、owner/repo#subdir、完整 git/SSH URL,以及本地路径。不带 --trust 安装时,Grok 会展示来源、警告安装会激活插件的钩子、MCP 服务器和技能,然后停下来等你确认。

官方文档在「Trust and security」一节把安全模型讲得非常清楚,这是理解插件系统的关键:插件以你的权限运行,要像对待任何要安装的软件一样对待它。启用(enable)一个插件会加载它的技能、命令和代理——这些都是「提示类」内容;而信任(trust)是另一回事,它决定插件的「代码类」组件能不能跑:即使启用了,插件的 hooks、MCP 服务器、LSP 服务器在信任之前都保持不活动。~/.grok/plugins/ 下的插件自动受信任;项目级 .grok/plugins/ 下的插件需要显式信任(安装时加 --trust)。信任的插件若带 .mcp.json 服务器,会像其他 MCP 配置一样挂到会话上,子代理也会继承。配置层面还能用 [plugins] 小节做精细控制:paths 追加插件目录、disabled 跳过某些插件、enabled 强制开启某些插件;插件默认是关闭的,所以想用就得列进 enabled。企业想彻底隐藏插件界面,可在 pager.toml 里设 disable_plugins = true。

插件发现位置也有优先级与信任差异,官方表格整理如下:

位置 作用域 信任
_meta.pluginDirs(session/new、session/load 请求) 单次会话 自动信任,会话结束即失效
--plugin-dir(grok agent … stdio 进程级参数,可重复) 单个 agent 进程 自动信任
.grok/plugins/ 项目(随版本库共享) 需要信任
~/.grok/plugins/ 用户(所有项目) 自动信任
[plugins].paths(配置指定) 自定义目录 视位置而定

打造并分发自己的 marketplace

自建 marketplace 需要三样东西:一个 git 仓库、每个插件一个文件夹、一个把它们列出来的索引文件。官方给出的典型目录结构长这样:

my-org-plugins/
  .grok-plugin/
    marketplace.json      # Grok 读取的索引(必需)
    plugin-index.json     # 可选:给市场浏览器展示更丰富信息的目录
  plugins/
    gdrive/
      plugin.json         # 可选清单
      skills/gdrive/SKILL.md
      .mcp.json           # 该插件附带的 MCP 服务器

索引文件 marketplace.json 声明市场名称并列出每个插件;每个插件条目可以指向本仓库内的目录("type": "local")或另一个独立仓库("source": "url",官方建议钉住 sha 以便可复现安装——当企业开启「强制钉版本」策略时这是必需的):

{
  "name": "My Org Plugins",
  "description": "Internal skills and tools",
  "plugins": [
    {
      "name": "gdrive",
      "description": "Search and edit Google Drive, Docs, Sheets, and Slides",
      "category": "productivity",
      "source": { "type": "local", "path": "./plugins/gdrive" }
    }
  ]
}

可选的 plugin-index.json 目录让市场浏览器在安装前就能展示每个插件的技能、命令、钩子和代理清单(纯展示用途,安装不需要它,团队一般放在 CI 里生成)。发布前用 grok plugin validate 校验、grok plugin tag 打版本标签。组织级下发则有两条受管通道:managed_config.toml 与用户配置合并,用来给全员下发 marketplace 源并开启插件;managed-settings.json 是受保护的政策文件,优先级高于用户、项目与本地配置且不可被覆盖,用来做白名单——strictKnownMarketplaces 限定只允许添加哪些源,allowedMcpServers 用通配符限定哪些 MCP 服务器能跑(注意:通配符必须带 scheme,*://… 或裸域名模式永远不会匹配),[marketplace] require_sha = true(或环境变量 GROK_MARKETPLACE_REQUIRE_SHA=1)则拒绝一切未钉到完整 commit sha 的远程安装。插件钩子运行时还会额外拿到两个环境变量:GROK_PLUGIN_ROOT(插件安装目录的绝对路径)和 GROK_PLUGIN_DATA(插件可写数据目录,用于状态、缓存与日志),同一钩子的 env 里想覆盖它们是无效的——插件适配器保证官方值永远胜出。

你现在应该掌握了什么:插件的定义与合法组件(技能/命令/代理/钩子/MCP/LSP)、「安装 ≠ 启用 ≠ 信任」的三层安全模型、marketplace 两步式工作流与全套 grok plugin 命令、发现位置优先级表、自建 marketplace 的三要素(仓库 + 插件目录 + 索引),以及组织级下发的 managed_config.toml 与 managed-settings.json 双通道。注意:以上命令与行为细节以当前版本官方文档为准,发行版之间可能存在差异。

Hooks 钩子:在会话的关键时刻插入你的代码

前三类机制都围绕「给模型更多能力」,而 Hooks 的思路反过来:在模型干活的关键节点上,插入你自己的代码来观察、约束、修正它。官方文档给 Hooks 下的定义是:钩子(hook)是 Grok 在特定生命周期事件发生时调用的一条 shell 命令或一个 HTTP 端点。它能做到的事情,文档里给了五条极具画面感的示例:拦截动作——一个 PreToolUse 钩子可以在危险命令真正执行前把它否决掉;让 Agent 继续干活——一个 Stop 钩子可以阻止 Agent 结束当前回合,直到某个条件成立(比如测试套件通过),并把原因回喂给模型;响应事件——一个 PostToolUse 钩子可以把每次工具执行记进日志文件;修正已发生的调用——PostToolUse 钩子还能告诉模型某个工具结果意味着什么,甚至直接替换模型将要读取的输出——比如抹掉一段日志里的密钥、裁剪一屏刷屏的日志行,而真实结果始终留在记录里;准备上下文——SessionStart 钩子可以导出环境变量或运行初始化脚本。

事件图谱:什么时刻会触发什么

官方文档把事件按节奏分成三档:每个会话一次(SessionStart、SessionEnd)、每个回合一次(UserPromptSubmit、Stop、StopFailure)、回合内每次工具调用(PreToolUse、PostToolUse、PostToolUseFailure),此外还有若干补充事件。完整事件表如下(阻塞性表示能否借此改变控制流):

事件 触发时机 能否阻塞
SessionStart 会话开始(子代理自身会话不触发) 否
UserPromptSubmit 你提交提示词 是:可拦截该提示词
PreToolUse 工具即将运行 是:可否决
PostToolUse 工具运行结束(含内置逻辑错误,如命令非零退出) 否,但可回喂模型并替换其看到的输出
PostToolUseFailure 工具调度失败或 MCP 工具返回错误 否,但可提供 additionalContext
PermissionDenied 权限系统否决一次工具调用 否
Stop Agent 回合正常结束 是:可阻止停止,让 Agent 继续
StopFailure 回合因 API 错误结束 否
StopCancelled 回合未完成就结束(中断、拒绝授权、达回合上限等) 否
Notification 需要用户注意的事件(idle_prompt、permission_prompt、task_complete…) 否
SubagentStart / SubagentStop 子代理开始 / 回合结束 SubagentStop 可阻止停止
PreCompact / PostCompact 会话压缩(compaction)前后 否
SessionEnd 会话结束 否

文档特别解释了几组容易混淆的语义。Stop、StopFailure、StopCancelled 是一个回合结束时「三选一」的报告:正常完成报 Stop,API 报错报 StopFailure,被打断(Ctrl+C、拒绝授权、--max-turns 上限、无进展自动退出等)报 StopCancelled。区分它们对做「忙碌/空闲指示器」尤其重要——文档给的完整方案要注册五个事件:UserPromptSubmit 标记忙碌,Stop/StopFailure/StopCancelled 按结局结算,idle_prompt 通知作为兜底(因为 bash 模式、内置斜杠命令等少数回合一个都不报)。另外 Stop 是「闸门」(gate):它阻止停止后模型会再来一轮,每回合最多续 8 次,之后强制结束;而 StopCancelled 永远不能阻塞——回合已经结束了,让钩子重新打开一个用户故意停掉的回合是在跟用户作对。还有个细节:会话结束时还会额外触发一次 Stop(reason 为 channel_closed 或 shutdown),计数脚本要用 reason == "end_turn" 过滤掉它。

配置格式:JSON 文件、命令与 HTTP 两类钩子

钩子放在 ~/.grok/hooks/*.json(全局,永远受信任)、项目级 .grok/hooks/*.json(需先信任文件夹,跑 /hooks-trust 或加 --trust 启动,信任记录在 ~/.grok/trusted_folders.toml,与仓库级 MCP/LSP 共用同一道闸)、兼容来源(Claude 的 settings.json、Cursor 的 hooks.json)、配置 TOML、受管配置与插件里,全部合并生效。一个典型的 JSON 文件可以同时定义多个事件、多个 matcher 分组:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "bin/safety-check.sh", "timeout": 10 }
        ]
      }
    ],
    "PostToolUse": [
      {
        "hooks": [
          { "type": "command", "command": "bin/log-activity.sh" }
        ]
      }
    ]
  }
}

字段语义:顶层键是事件名(未知事件名会被跳过,所以共享的 Claude/Cursor 配置文件也能整文件加载);matcher 是可选正则,决定哪些调用触发本组钩子——工具事件匹配工具名、Notification 匹配通知类型、SubagentStart 匹配子代理类型、StopCancelled 匹配原因(user_interrupt、permission_rejected、max_turns、no_progress 等)、StopFailure 匹配错误类别(rate_limit、authentication_failed、invalid_request、server_error、max_output_tokens、unknown);空 matcher 匹配一切。type 只有两种:"command"(跑脚本或 shell 一行式,路径相对 JSON 文件所在目录)和 "http"(把完整事件 JSON POST 到 url)。timeout 默认 5 秒,但 Stop、SubagentStop、PostToolUse 这类常跑构建/测试的闸门默认 600 秒。matcher 里还能用 Claude 风格的别名:Bash 会同时匹配 Grok 自己的 run_terminal_command,Edit/Write 对应 search_replace,WebSearch 对应 web_search,Task 对应 spawn_subagent——方便把 Claude Code 的钩子原样搬过来。

事件触发时,Grok 按四步解析:先选出所有 matcher 命中的分组;再按配置顺序逐个运行组内 handler(每个 handler 都从 stdin 收到 JSON 事件,直到某个返回 deny 才中断链);然后应用决策——PreToolUse 的首次 deny 会否决这次调用并把原因展示给模型,updatedInput 会改写工具入参(所有 handler 跑完后才应用,后写者胜),Stop/SubagentStop 的 block 让 Agent 继续干活,PostToolUse 则把 block 原因和 additionalContext 随工具结果一起交给模型;最后是默认放行(fail-open)原则:任何 handler 超时、崩溃、输出畸形都只记录到滚动区,绝不阻塞动作——唯一例外是 PreToolUse 的 updatedInput 改坏了导致过不了工具 schema,这种「改写无法安全执行」的情况会以非法输入错误拦截调用。

写一个钩子脚本:输入、输出与退出码

钩子脚本的输入是 stdin 上的一整份 JSON 事件,所有事件都带公共字段:hookEventName、sessionId、cwd、workspaceRoot、timestamp、permissionMode、promptId,再叠加事件特有字段(如 PreToolUse 的 toolName、toolInput)。官方示例里 PreToolUse 事件的 payload 大致是:

{
  "hookEventName": "pre_tool_use",
  "sessionId": "abc-123",
  "cwd": "/Users/you/project",
  "toolName": "run_terminal_command",
  "toolInput": { "command": "npm test" },
  "timestamp": "2026-04-14T12:00:00Z"
}

输出则按事件类型分三套协议。阻塞型钩子(PreToolUse)往 stdout 写 JSON 决策:{"decision": "allow"} 放行、{"decision": "deny", "reason": "..."} 否决、{"decision": "ask", "reason": "..."} 转人工确认(会让本次调用进入权限询问流程,且不会因 always-approve、auto 模式、已存授权等而被静默放行)、{"decision": "defer"} 表示「没意见」,走正常权限流程;此外 hookSpecificOutput.updatedInput 可以静默改写工具入参(模型不知道、不写滚动区),additionalContext 可以在调用完成后给模型捎句话(以系统提醒标签包裹并署名钩子,超过一万字符会被截断)。PostToolUse 钩子跑在工具之后、拦不住任何东西,但它的 stdout 会被读取——因为它决定模型接下来看到什么:decision: "block" + reason 是「告诉模型出问题了」而非中断调用,updatedToolOutput 可以直接替换模型读到的那份工具结果(内置工具必须按该工具自己的输出形状回传,拿事件里给的 toolResult 改完再发回去最稳;MCP 工具没有形状校验、原样透传)。替换只作用于模型的副本——滚动区、转录、遥测里永远是原始结果,所以你用它给模型「打码」不会把你自己也蒙在鼓里。Stop 闸门写 {"decision": "block", "reason": "..."} 阻止结束并让模型再来一轮,写 {"continue": false, "stopReason": "..."} 强制结束(优先级最高),exit 2 带 stderr 也能阻止。退出码约定:0 放行、2 是显式否决/阻止(PostToolUse 下 exit 2 会把 stderr 喂给模型——文档专门警告:用 run_checker; exit $? 这类写法收尾的日志钩子,会在 checker 以 2 退出时把输出灌给模型,记得显式 exit 0)、其他码一律 fail-open。

官方文档给了一个完整的「安全外壳守卫」示例,语义非常清晰:匹配 Bash 工具,脚本里用 jq 取出命令,命中破坏性模式就 deny:

#!/bin/sh
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.toolInput.command // empty')

# Block destructive patterns
if echo "$CMD" | grep -qE '(rm -rf /|mkfs|dd if=|:(){ :|& };:)'; then
  echo '{"decision": "deny", "reason": "Blocked potentially destructive command"}'
  exit 2
fi

echo '{"decision": "allow"}'

配套的 JSON 注册(放在 ~/.grok/hooks/ 下,脚本放同目录 bin/ 里最稳妥,路径相对 JSON 文件解析):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "bin/safe-shell.sh", "timeout": 5 }
        ]
      }
    ]
  }
}

钩子进程还能拿到一组注入的环境变量:GROK_HOOK_EVENT(事件名)、GROK_HOOK_NAME、GROK_SESSION_ID、GROK_WORKSPACE_ROOT、兼容别名 CLAUDE_PROJECT_DIR;插件来源的钩子另有 GROK_PLUGIN_ROOT 与 GROK_PLUGIN_DATA。这些变量是保留的——你在 hook 的 env 字段里给它们赋值会在加载时被剥掉并告警。每个 handler 也能通过 env 字段携带自己的变量。钩子也可以直接写进 TOML 配置([[hooks.PreToolUse]] 形式,与 JSON 结构一一对应),方便组织随受管配置一起下发。TUI 里用 /hooks 打开 Hooks 标签页管理:r 重新加载、a 按路径添加、Space 启停单个钩子、f 过滤状态;还有 /hooks-list、/hooks-trust、/hooks-untrust 等斜杠命令。

官方给钩子作者的安全忠告值得全文背诵:全局钩子以你的用户权限运行,要像对待 shell 脚本一样对待它;项目钩子必须过文件夹信任这一关,防止恶意仓库搞供应链攻击;HTTP 钩子会把会话数据发出去,只连可信端点;PostToolUse 钩子决定模型读到什么——它能往结果里夹带指令或整体替换输出,所以它的可信度要和 PreToolUse 闸门同等对待(好在滚动区与转录始终保留原始输出,替换对你永远可见)。最佳实践就五条:钩子要快(长任务放后台或用异步,别阻塞 UI);想拦就用显式 deny(fail-open 意味着崩掉的钩子拦不住任何东西,策略必须在脚本里自己处理错误并输出明确决策);路径写绝对或相对 JSON 文件;用 /hooks 面板验证加载与匹配;项目钩子进版本库但绝不含秘密。

你现在应该掌握了什么:Hooks 的本质(事件驱动的脚本/HTTP 回调)、完整事件图谱与三档节奏、阻塞型与非阻塞型事件的区别、JSON/TOML 配置格式与 matcher 语义、「四步解析 + fail-open」执行模型、三类输出协议(决策 / PostToolUse 替换 / Stop 闸门)、退出码约定,以及安全模型与五条最佳实践。

四者对比:一张表理清选型

讲完四个机制,我们站在选型视角把它们放在一起比一比。下面的对比表是我基于官方文档四章内容整理的速查卡,供你在设计自己的 Agent 环境时对号入座:

维度 MCP 服务器 Skills Plugins Hooks
本质 外部工具接入协议(进程/远端服务) 可复用提示包(目录 + SKILL.md) 内容打包与分发单元 生命周期事件回调(脚本/HTTP)
解决的核心问题 模型手不够长:接外部系统能力 每次重复解释:固化流程与做法 逐个配置太散:批量安装与团队分发 Agent 不可控/不可观测:拦截、审计、自动化
内容形态 服务端暴露的工具(命令式可调用) 指令文本(教模型怎么做) 技能+命令+代理+钩子+MCP 配置的合集 事件触发的 shell 命令或 HTTP POST
生效时机 会话中随时可发现与调用 命中 description 自动激活或斜杠命令手动触发 安装→启用→信任后组件全部就位 生命周期事件发生时
作用范围 工具命名空间(server__tool) 技能名(可带作用域前缀) 插件名限定(plugin:name) 事件 + matcher 正则
编写/接入成本 中:要起服务或对接端点 低:一个 md 文件 中:目录结构 + 索引 + 发布 中高:脚本 + JSON 协议 + 决策语义
运行风险 以你的权限跑外部代码 低(提示注入风险需注意) 高:代码类组件要显式信任 高:以你的权限执行,需信任把关
典型场景 接 GitHub/数据库/内部 API 提交规范、Review 流程、部署步骤 团队工具集、企业标准化分发 安全守卫、审计日志、测试门禁、忙碌指示

你现在应该掌握了什么:四个机制在「本质、解决什么问题、生效时机、成本与风险」五个维度上的差异,能根据「要接外部系统 / 要固化流程 / 要批量分发 / 要设规则」四种诉求快速选型。

踩坑经验:文档字缝里读出来的教训

这一节把我读文档时注意到的、新手最容易踩的坑整理成 ❌/✅ 对照。全部依据官方文档中的明确表述整理:

MCP 篇

❌ 把密钥直接写进会被提交的 .grok/config.toml,然后用 grok mcp list 看着它心里发慌。✅ 用 ${VAR} 或 ${VAR:-default} 引用环境变量——url、command、args、env、headers 在加载时都会展开;官方明说 header 与环境变量值是原样存储的。

❌ 项目配置和全局配置里定义了同名 MCP 服务器,指望两边字段自动合并取长补短。✅ 记住官方原话:项目版本会整个替换全局版本,字段不合并;不想被替换就换名字。

❌ 给远端服务套 npx mcp-remote <url> 的 stdio 代理,每个会话白养一个子进程。✅ 原生 HTTP/SSE 端点直接写 url 形式,Grok 自己处理 OAuth 注册。

❌ 服务器首次启动要下载包,30 秒超时一到就报错,然后怀疑人生。✅ 调大 startup_timeout_sec,或用全局的 MCP_TIMEOUT(毫秒)与 GROK_MCP_STARTUP_TIMEOUT_SECS 改默认值。

❌ MCP 工具吐回几 MB 日志把上下文撑爆。✅ 了解默认 20000 字节的截断阈值,用 GROK_MAX_MCP_OUTPUT_BYTES 或 [mcp] max_output_bytes 调整,完整载荷会落在会话 mcp/ 目录下。

❌ 服务器握手失败只能干瞪眼。✅ tail -f ~/.grok/logs/mcp/<server>.stderr.log 看标准错误;grok mcp doctor 体检;RUST_LOG=debug GROK_LOG_FILE=/tmp/grok.log grok 开调试。

Skills 篇

❌ 以为把技能目录写进 .gitignore 就能藏起来。✅ 官方明说技能发现不读 .gitignore,文件在磁盘上就会被加载;想隐藏用 [skills] ignore,想禁用用 [skills] disabled。

❌ description 写「Create git commits」这种大而化之的话,结果模型永远不自动触发。✅ description 是自动调用的唯一依据,要写清「做什么 + 何时用 + 触发短语」,官方例句值得逐字学习。

❌ 一个技能塞下「deploy 和 rollback 两件事」,激活时模型无所适从。✅ 一个技能只做一件事,拆开写效果更好。

❌ 技能名跟内置命令撞了,以为必须改名。✅ Grok 两个都保留:内置占裸名,技能自动获得 local:/repo:/user:/插件名: 前缀限定名,想独占裸名再改名。

Plugins 篇

❌ 装了插件就以为万事大吉,结果钩子不跑、MCP 服务器不出现。✅ 记住三层状态:安装 ≠ 启用 ≠ 信任——装完要在 [plugins].enabled 里启用或面板按 Space,代码类组件还要 --trust 或放进自动信任的 ~/.grok/plugins/,之后按 r 重载或开新会话。

❌ 以为插件能顺带把 Python 依赖、原生二进制装到用户机器上。✅ 插件只送文件不送运行时;辅助脚本的运行环境必须本来就有,二进制要走部署渠道单独交付。

❌ 企业环境里装了个没钉版本的远端插件。✅ 组织开了 require_sha 时,只接受 owner/repo@<sha> 精确提交或带 sha 的 marketplace 目录。

❌ 在 allowedMcpServers 里写 *://example.com/* 或裸域名想放行一切。✅ 通配符必须带 scheme;*://… 与无 scheme 模式永远不匹配,还会在启动时打警告。

Hooks 篇

❌ 钩子脚本写崩了/超时了,还指望它拦住危险命令。✅ 一切钩子故障都 fail-open(超时、崩溃、畸形输出只记录不拦截),想拦必须让脚本跑完并输出明确的 {"decision":"deny","reason":"..."}——文档原话:把错误处理写进脚本里。

❌ 用 run_checker; exit $? 收尾的 PostToolUse 日志钩子,某天开始往模型嘴里灌 checker 的输出。✅ PostToolUse 的 exit 2 语义已改为「把 stderr 喂给模型」——mypy、grep、pytest、argparse 都爱用 2 表示「没匹配/用法错」,日志钩子记得显式 exit 0。

❌ 用 Stop 一个事件做「忙碌/空闲」指示器,回合被打断后 UI 永远显示忙碌。✅ 完整方案是五连注册:UserPromptSubmit + Stop/StopFailure/StopCancelled + idle_prompt 兜底,还要按 promptId 关联、忽略旧回合报告、见到 subagentType 提前退出。

❌ 项目钩子不触发,反复改文件怀疑格式。✅ 大概率是文件夹没信任:跑 /hooks-trust(或 --trust 启动),信任记录在 ~/.grok/trusted_folders.toml。

❌ 把 Grok 的输出协议按 Claude Code 的 snake_case 字段名硬编码。✅ Grok 的 stdin 信封是 camelCase(stopHookActive、backgroundTasks),但也提供了兼容别名;移植 Claude 钩子时先对照官方「Porting Claude Code stop hooks」清单,比如 grok 只发 shell/monitor/subagent 三类后台任务、权限模式取值是 default/auto/plan/bypassPermissions。

你现在应该掌握了什么:四类机制最常见的失败模式与官方认可的解法,尤其是「密钥用 ${VAR}」「同名即整体替换」「安装≠启用≠信任」「fail-open 意味着显式 deny 才是策略」「PostToolUse exit 2 会把 stderr 喂给模型」这几条反直觉规则。

总结

带读完四篇官方文档,把核心结论浓缩成六条,方便你带走:

  1. 四层扩展各司其职、彼此咬合:MCP 给工具、Skills 给做法、Hooks 给规则、Plugins 负责把前三者打包分发;画一张架构图放桌面,选型时对号入座。
  2. MCP 是「协议红利」最明显的入口:生态里现成的服务器数以百计(官方 registry 在 modelcontextprotocol/servers),stdio 管本地、HTTP/SSE 管远端,grok mcp add 一条命令接入,优先原生 URL 形式、密钥走 ${VAR}。
  3. Skills 是投入产出比最高的自定义:一个目录加一个 SKILL.md 就能固化一套流程;description 写具体、一个技能一件事、项目技能进版本库,团队共享从写好 description 开始。
  4. Plugins 的安全模型是「三层闸」:安装只搬文件,启用才加载提示类内容,信任才放行代码类组件(hooks/MCP/LSP);从可信来源安装、必要时用受管策略钉版本,是把插件生态用进企业的前提。
  5. Hooks 是工程化的抓手:想拦截危险命令用 PreToolUse 的显式 deny,想当测试门禁用 Stop 闸门,想做审计用 PostToolUse 落日志,想做状态指示器就五连注册;永远记住 fail-open——策略必须由脚本自己明确表达。
  6. 一切以当前版本官方文档为准:Grok Build 迭代很快,本文是文档快照式带读,命令与行为(比如 --env 语法、服务器命名规则、钩子输出协议)随时可能演进,动手前先 grok inspect 看本机实际行为。

参考资料

  • MCP Servers(官方 user-guide 07):https://raw.githubusercontent.com/xai-org/grok-build/main/crates/codegen/xai-grok-pager/docs/user-guide/07-mcp-servers.md
  • Skills(官方 user-guide 08):https://raw.githubusercontent.com/xai-org/grok-build/main/crates/codegen/xai-grok-pager/docs/user-guide/08-skills.md
  • Plugins(官方 user-guide 09):https://raw.githubusercontent.com/xai-org/grok-build/main/crates/codegen/xai-grok-pager/docs/user-guide/09-plugins.md
  • Hooks(官方 user-guide 10):https://raw.githubusercontent.com/xai-org/grok-build/main/crates/codegen/xai-grok-pager/docs/user-guide/10-hooks.md
  • Grok Build 仓库 README:https://github.com/xai-org/grok-build
  • MCP 协议规范:https://modelcontextprotocol.io
  • MCP 官方服务器 Registry:https://github.com/modelcontextprotocol/servers

(本文为技术带读笔记,非 xAI 官方出品;文中「以当前版本官方文档为准」之处请以你安装版本的官方文档为最终依据。)