
很多人在网上搜“Claude 插件”的时候看到的多半是浏览器扩展、油猴脚本、各种套壳客户端。但今天要聊的不是这些而是 Claude Code 自带的官方插件体系——也就是 claude-plugins 这套机制。它解决的问题其实特别朴素你在终端里用 Claude 写代码、跑任务总有那么一些操作反复出现比如提交前要统一做代码审查、每次提交流程要按固定格式整理变更说明、跑完测试之后要汇总日志。这些事如果每次都靠临时打一大段提示词既费 token 又不稳定。官方插件机制就是把这类流程固化下来变成随手调用的斜杠命令、自动触发的钩子脚本以及专职干某类活的子代理。这篇内容适合两类人一类是刚开始用 Claude Code、想把工作流变得更顺手的朋友另一类是已经在用、想把手头半自动流程正式做成插件分享给同事的人。下面的内容基本按我实际搭建插件的顺序来写从目录结构到踩坑记录尽量让你看完就能照着复现而不是只记住几个名词。1. 官方插件的物理形态一个文件夹就是一套工作流1.1 目录即插件plugin.json 是身份证我最早翻官方文档时的一个直观感受是这个插件定义比很多同类工具都轻。一个插件本质上就是一个目录目录里必须有一个.claude-plugin/plugin.json文件。这个文件是插件的“身份证”加“清单”声明了这个插件叫什么、干什么用、包含哪些命令、哪些 Agent、哪些 Hook。其余内容全部围绕这个文件展开按约定放在子目录里在 plugin.json 里声明相对路径。目录大概是这个样子my-plugin/ ├── .claude-plugin/ │ └── plugin.json ├── commands/ │ └── code-review.md ├── agents/ │ └── docs-writer.md ├── hooks/ │ └── pre_tool_use.sh └── README.md对这个结构我想强调三点。第一插件根目录的名字最好和 plugin.json 里的 name 保持一致虽然技术上不强制但后来你要把它加进市场、让同事安装时名字一致能少很多困惑。第二plugin.json 里声明的命令、Agent、Hook 路径全部相对插件根目录。我见过有人图省事写绝对路径结果换一台机器整个插件立刻废掉。第三插件的生效范围只在 Claude Code 会话里它不会变成系统全局的程序也不是一个常驻后台服务。理解这个边界很重要这决定了你该把插件用于“工作流自动化”而不是“操作系统自动化”。提示插件目录完全可以交给 Git 管理。但别往里塞大型二进制文件Claude Code 会扫描插件目录塞一堆体积巨大的东西加载阶段明显变慢。1.2 插件能承载的三类核心内容官方插件机制核心装三类东西类型作用触发方式Slash Command斜杠命令把一段精心设计的提示词封装成命令用户在对话里手动输入/命令名Hook钩子在会话或工具调用的特定节点执行脚本自动触发无需用户干预Agent子代理定义一个专职角色让主任务委派给它主 Claude 会话按需把子任务交给 Agent另外插件声明里也可以附带 MCP server 配置但那个我建议有经验的用户再碰新手阶段先玩明白三件套就够了。这三类东西的选择逻辑我后面会展开。这里先给一句总结斜杠命令解决“你反复输入同一个需求”的问题Hook 解决“你反复批准或检查同一个动作”的问题Agent 解决“某个环节需要固定角色和固定产出格式”的问题。三者相互独立又可以组合在同一个插件里形成一套完整的工作流。1.3 别把官方插件和浏览器扩展混为一谈我经常在群里看到有人问“有没有插件能让 Claude 网页版自动发消息”或者“能不能用插件改网页 UI”这些需求对应的都不是官方插件。Claude Code 的插件跑在终端环境里权限模型继承自 Claude Code 本身它能读文件、写文件、执行命令但这些动作都发生在当前项目上下文里并且受到权限审批机制约束。你要控制浏览器页面、操作 GUI那得另找浏览器自动化工具而不是套在 Claude Code 里的插件。搞清楚这个边界你就不会拿插件做那些它做不到的事也不会对它的能力产生不切实际的预期。官方设计哲学其实是克制的它让插件在代码工作流内足够强大但不给它超出边界的系统权限。2. plugin.json 怎么写每个字段为什么不能省2.1 一个可以直接抄的最小配置先给一个最小可用版本{ name: dev-flow, description: 开发工作流增强插件代码审查、文档生成、自动化检查, version: 0.3.0, author: your-name, license: MIT, commands: [ { name: code-review, description: 对当前改动执行一轮代码审查输出风险清单, path: commands/code-review.md } ], agents: [ { name: docs-writer, description: 根据代码改动生成和更新技术文档, path: agents/docs-writer.md } ], hooks: { PreToolUse: [ { matcher: Bash, hooks: [ { type: command, command: hooks/pre_tool_use.sh } ] } ] } }这份配置就是前面目录结构的完整声明。它定义了三块commands 声明一个名为 code-review 的斜杠命令agents 声明一个 docs-writer 子代理hooks 里声明了一个 PreToolUse 钩子匹配 Bash 工具调用执行hooks/pre_tool_use.sh。结构上没有任何多余的东西但已经是一个五脏俱全的插件了。2.2 字段背后的实际意义name 是插件的唯一标识内部识别靠它冲突会导致加载异常所以建议小写加连字符。description 会在/plugin面板和市场列表里展示别写“一个很好用的插件”这种空话最好让同事一眼就知道解决什么问题。version 遵循语义化版本号这个字段在市场更新机制里特别关键本地和远程版本靠它比较来决定要不要拉新。hooks 里的 matcher 表示钩子匹配哪些工具调用最常用的是Bash但也可以匹配Read、Edit、Write等。commands 和 agents 里的 path 指向具体 Markdown 文件。官方把命令和代理设计成 Markdown不是偶然因为它们的核心就是“元信息加提示词”用 Markdown 写方便版本对比也方便团队里不太写代码的人直接看懂。2.3 我在 plugin.json 上踩过的三个坑第一个坑是 name 用了大写和下划线。Claude Code 解析插件名比较严格我最早写了个My_Plugin结果安装后一直找不到改成my-plugin就好了。第二个坑是 version 忘了更新。插件走市场方式分发后版本号不动同事那边永远拉不到新逻辑排查半天才发现是版本号没变。第三个坑最隐蔽把 hooks 的 matcher 写成了工具名而不是事件名。PreToolUse、PostToolUse这类是事件名不是“Bash”这种工具名事件名写错不会报错钩子就是静默不触发。你如果发现钩子完全没反应先回这里检查。3. 第一个斜杠命令把代码审查流程固化下来3.1 斜杠命令的本质一段带元信息的提示词一个斜杠命令本质是一个 Markdown 文件顶部是 YAML frontmatter下面正文是提示词正文。你输入/code-review时Claude 会把整个文件当作上下文的一部分相当于它“背”下了你精心调整过的提示词。frontmatter 里几个字段--- name: code-review description: 对当前 git 改动执行代码审查输出风险清单 allowed-tools: Bash, Read, Glob, Grep model: sonnet ---allowed-tools 用来限制命令执行时能调用哪些工具审查类任务我只给只读类工具防止它顺手改文件。model 可以指定这个命令用更强的模型还是更快的模型成本和效果之间自己权衡。description 别小看Claude 在判断何时调用这个命令时description 就是它的依据。3.2 一段能直接抄的代码审查命令--- name: code-review description: 对当前 git 改动执行代码审查输出风险清单 allowed-tools: Bash, Read, Glob, Grep model: sonnet --- 请对当前仓库中尚未提交的改动进行一轮代码审查。 执行步骤 1. 先运行 git diff --stat 和 git diff 获取改动概览。 2. 对每个改动的文件重点检查逻辑边界、异常处理、安全性尤其是用户输入、文件路径、命令拼接、可维护性。 3. 如果改动涉及依赖或配置变更指出影响范围。 输出格式要求 - 按严重程度分级严重 / 建议 / 一般 - 每个问题给出文件位置、问题描述、修改建议 - 最后给一句总体评价不要超过 50 字 注意不要为了追求内容多而输出没营养的建议。没有问题的文件直接跳过。看到这段你应该能明白为什么我说命令的核心是提示词。平时你怎么在对话里要求 Claude现在就怎么去写这个文件区别在于格式被稳定下来、可以在$ARGUMENTS位置插入用户输入比如/code-review --strict这种带参数用法、以及团队共享时所有人用同一套标准而不是十个人十种审查风格。我把审查要求写得非常具体先跑 git diff再按严重程度分级输出最后不超过 50 字总评。这些细节都是从实际使用里磨出来的写得太笼统模型容易给你输出一堆“无营养但正确”的话看着专业实际没用。3.3 命令打磨的两点体会第一正文里明确执行顺序比直接说“你看着办”好得多。虽然模型本身能拆解任务但你给出确定性的流程后输出质量稳定很多对一个反复使用的命令稳定性比灵活性重要。第二description 要写清楚边界。“对当前 git 改动执行代码审查并输出风险清单”和“检查代码”听起来差不多后者会让模型在很多不相关场景下误调用这个命令所以描述越贴近你的真实使用场景越好。我后来把 description 调了几轮误调用率明显下降。4. Hooks 钩子让插件在关键节点自己动手4.1 先看透 Claude Code 的一次调用生命周期Hook 的设计思路是允许你在会话的某些节点插入自定义脚本。官方钩子事件大致有这些事件触发时机常见用途UserPromptSubmit用户提交消息后、Claude 处理前注入上下文、检查敏感词PreToolUse工具被执行前放行 / 拒绝工具调用PostToolUse工具执行完成后检查输出、触发后续处理NotificationClaude 需要用户批准时自动批准特定操作StopClaude 生成回答后记录日志、汇总信息SubagentStop子代理执行完处理子代理结果SessionStart / SessionEnd会话开始 / 结束初始化环境、清理状态我不打算每个事件都铺开讲那样反而记不住。实际工作中你只需要把 PreToolUse 和 PostToolUse 玩熟就能解决九成自动化需求。PreToolUse 在工具执行前触发你可以决定放行、拒绝或者交回人工审批PostToolUse 在工具执行后触发你可以检查输出、做记录、触发后续动作。剩下的事件属于锦上添花遇到具体需求再查文档不迟。4.2 一个真实的 PreToolUse 拦截脚本场景团队希望npm test这类安全命令直接放行不用每回弹审批框但rm -rf这类危险命令必须拦下来。PreToolUse 就能做#!/usr/bin/env bash # hooks/pre_tool_use.sh input$(cat) tool_name$(echo $input | python3 -c import sys, json; datajson.load(sys.stdin); print(data.get(tool_name, ))) tool_input$(echo $input | python3 -c import sys, json; datajson.load(sys.stdin); print(json.dumps(data.get(tool_input, {})))) if [[ $tool_name Bash ]]; then if echo $tool_input | grep -q npm test; then echo {hookSpecificOutput: {hookEventName: PreToolUse, permissionDecision: approve, permissionDecisionReason: npm test 为安全命令自动放行}} exit 0 fi if echo $tool_input | grep -qE rm -rf|mkfs|dd ; then echo {hookSpecificOutput: {hookEventName: PreToolUse, permissionDecision: deny, permissionDecisionReason: 检测到危险命令禁止执行}} exit 0 fi fi # 默认交回正常审批流程 echo {hookSpecificOutput: {hookEventName: PreToolUse, permissionDecision: ask}} exit 0这段脚本的几个关键点。输入钩子从标准输入读一个 JSON里面至少包含tool_name和tool_input。输出通过标准输出返回 JSONhookSpecificOutput里放permissionDecision值可以是approve、deny、ask。无论走哪个分支最后都要正常exit 0脚本异常退出会被 Claude Code 视为钩子失败甚至可能终止整个工具调用。另外注意我用的是 python3 解析 JSON而不是 jq原因后面排查部分会讲。4.3 调试钩子的土办法但真管用Hook 最容易出问题的地方不是逻辑而是 JSON 解析。字段名大小写写错、输入里某个字段缺失都会静默失败。我的调试套路是三步先手工构造一份 JSON 喂给脚本看输出是否合法然后在 Claude Code 里实际触发一次开--debug模式看日志重点看 stderr最后检查脚本可执行权限chmod x是最容易被忽略的一步很多“失灵”其实只是没有执行权限。注意钩子脚本里不要写任何会等待用户输入的交互逻辑。钩子是自动流程的一部分一旦阻塞整个会话都会卡住等你这个体验非常糟糕。5. 插件里的 Agent把重复的“角色扮演”变成正式岗位5.1 斜杠命令和 Agent 的分工经常有人问命令和 Agent 不都是提示词吗区别在哪我的理解是命令是“固定流程的快捷键”Agent 是“可以独立干活的员工”。命令运行在主会话里你手动触发适合流程化输出Agent 运行在独立子会话主会话按需委派适合需要多轮探索和独立判断的子任务。工具调用次数多、过程繁琐的任务丢给 Agent 能避免主对话被过程刷屏。具体对比维度斜杠命令Agent触发方式用户手动输入/命令名主 Claude 会话根据情况自动委派运行载体当前主会话独立子会话使用场景固定、流程化的输出需要独立思考、多步执行的子任务工具权限通过 allowed-tools 限制通过 tools 限制独立配置5.2 我的文档 Agent 实例手头这个 docs-writer 是我在插件里挂的第一个 Agentfrontmatter 和正文如下--- name: docs-writer description: 根据代码改动编写和更新技术文档适合在功能变更后调用 tools: Read, Glob, Grep, Edit, Write model: sonnet --- 你是一名技术文档工程师团队约定如下 1. 你的目标是让“不了解本次改动的人”通过文档快速理解变更。 2. 文档风格简洁、结构化使用 Markdown英文变量名保留原文。 3. 每次写文档前先读取相关源码和现有文档确认不重复、不冲突。 4. 输出文件放在 docs/ 目录下文件名与模块名一致。 5. 如果现有文档已经过时优先更新它而不是新建文档。 重要约束 - 不要修改任何源代码文件。 - 如果信息不足明确列出“待确认清单”不要编造技术细节。挂上之后主会话只要判断“这次改动需要更新文档”就会自动把任务委派给 docs-writer用户端只看到子代理摘要不会被中间过程打断。实际用下来给 Agent 写“明确约束”比写“积极完成”效果明显更好约束它不要改源码、信息不足就列待确认清单、优先更新已有文档而不是新建这些规则让它的执行路径短了很多。没有约束的子代理会漫无目的地探索整个代码库耗时和 token 消耗都会暴涨。5.3 什么时候该拆 Agent什么时候别拆我的经验法则很简单任务需要 5 次以上工具调用且结果要为后续主会话服务拆 Agent任务只是“把这段文字整理成表格”用命令或直接对话任务需要强烈的领域角色立场比如安全评审、性能分析拆 Agent并且在前缀里把角色的立场讲透。另外Agent 的 model 字段也要刻意设计。文档生成这种任务我用更快更省的模型安全审查这种任务我用更强的模型。这一行配置长期下来对 token 成本的影响不小。6. 从本地到团队插件的安装、市场与版本管理6.1 三种加载方式三种适用范围官方插件支持几种加载方式我实际用下来是这样区分的方式使用方式适用场景本地目录claude plugin install /path/to/plugin自己开发调试个人插件目录放置到~/.claude/plugins/下个人常用开机即用Git 市场claude plugin marketplace add git地址再claude plugin install 插件名团队共享个人插件目录这个方式容易被忽略但很实用。你把自己常用的一些命令、Agent 放在~/.claude/plugins/下Claude Code 默认就会加载不用每次进项目都重新装一遍。团队场景则强烈建议走 Git 市场因为自动拉取、版本比较都靠它。具体命令参数以你本机claude plugin --help输出为准不同版本会有细微差异。6.2 搭一个内部市场的 marketplace.json{ name: team-hub, owner: { name: your-team, email: devexample.com }, source: git, plugins: [ { name: dev-flow, source: plugins/dev-flow, description: 开发工作流增强插件 }, { name: release-helper, source: plugins/release-helper, description: 版本发布辅助插件 } ] }这个文件放在仓库的.claude-plugin/marketplace.json路径下团队执行claude plugin marketplace add gityour-repo.git后就能在/plugin面板里看到并安装列出来的插件了。这里有个团队协作的小建议marketplace 仓库和插件源码仓库分开用或者说 marketplace 仓库只维护索引插件各自独立版本这样任何一个插件升级都不会阻塞其他插件。6.3 版本管理的三个细节第一发布新版本后记得同时更新 plugin.json 里的version和 marketplace 索引里的引用二者不匹配是拉不到更新的最常见原因。第二本地已安装的插件和市场里同名插件冲突时优先卸载本地版本否则/plugin面板里可能出现两个同名入口你根本分不清哪个生效。第三claude plugin list和claude plugin marketplace list这两个命令要勤用。看已装插件、看市场状态是排查所有“为什么没生效”问题的第一步。7. 实测高频坑位排查清单7.1 症状-原因速查表症状原因解决输入/命令名没有响应插件未加载或命令名冲突claude plugin list确认已装重命名冲突命令Hook 脚本不执行可执行权限缺失chmod x脚本Hook 执行了但会话卡住脚本阻塞等待输入去掉脚本里的交互逻辑输出 JSON 解析失败字段名拼写错误手工喂 JSON 测试脚本团队拉不到新版本plugin.json 的 version 没更新更新 version 并推送市场索引命令引用的文件找不到plugin.json 的 path 写错确认 path 是相对插件根目录这张表里的每一个坑我都真实踩过至少一遍。尤其是“权限缺失”和“版本没更新”这两个看起来低级但在团队环境里出现的频率比想象中高得多因为每个人都默认“别人已经处理好了”。7.2 我推荐的排查顺序遇到插件行为异常时别急着改代码按这个顺序来/plugin面板里看插件是否处于 active 状态。claude plugin list看插件版本确认加载的是不是你想测的那个版本。关掉所有自定义 Hook 后重试一次。如果恢复正常问题在 Hook否则问题在命令或 Agent 配置。开--debug模式观察日志里 hook 和命令的加载记录。这个“先状态、后脚本、再日志”的排查链路帮我排掉了至少 80% 的插件问题。很多时候不是脚本逻辑复杂而是环境、权限、版本这些外围因素在捣乱。我推荐在写任何复杂 Hook 之前先让脚本接受手工构造的 JSON 输入并返回固定输出这个验证过了再接入会话里做真实验证能省掉大量来回试错的时间。7.3 给插件长期维护的实在话最后说几条长期维护的体会。一个插件只解决“一类问题”。把代码审查、文档生成、日志分析全塞进一个插件后期维护成本会迅速膨胀命名、版本、权限都会变得混乱。命令的提示词要写在仓库里并且配 README。半年后回来看自己的插件如果 README 不像一个陌生人写的那说明写得太粗糙时间一长你自己都会忘了当初为什么这么设计。Hook 脚本优先选择 Python 写 JSON 解析而不是用 jq 各种猜。虽然 jq 一行能搞定但遇到字段不存在时jq 往往输出一个空值然后继续跑Python 的报错信息会让你少掉很多头发。不要追求一次写完美。先让一个命令跑通再逐步加 Agent、加 Hook每加一个都单独测一轮这样出问题时你能迅速定位。我个人实际操作中的体会是插件这套东西真正的门槛不在“写配置”而在“想清楚边界”。你愿意花时间把边界想清楚后面维护起来就会特别顺。反过来如果一上来就想做一个“万能插件”大概率两星期后自己都懒得用了。最后再分享一个小技巧每次新建插件先在里面放一个最简单的 hello 命令并跑通再开始填真实逻辑。这个小动作能帮你把“环境问题”和“逻辑问题”彻底分开后面的调试会轻松很多。