Claude Code 插件开发实战:从零开始创建你的第一个插件

95 次阅读

Claude Code 插件开发实战:从零开始创建你的第一个插件

如果你用过 Claude Code,应该已经感受到它在编程辅助上的强大能力。不过你可能不知道的是,从 1.0.33 版本开始,Claude Code 引入了一套插件系统,让你可以把自己的工作流、团队规范、常用操作打包成可复用的模块,随时在不同项目之间共享。

这篇文章会手把手带你走一遍完整流程——从创建一个最简单的插件,到添加技能(Skill)、钩子(Hook),再到在本地测试和日常使用。看完之后,你就能自己动手做一个属于自己的 Claude Code 插件了。

插件是什么,为什么需要它?

在 Claude Code 里,你其实一直在用类似"插件"的东西。.claude/ 目录下的自定义命令、技能文件、Hook 配置,这些都是在扩展 Claude 的能力。

那插件跟这些"散装配置"有什么区别呢?简单说就是打包和共享

对比项 散装配置(.claude/ 目录) 插件(.claude-plugin/
适用场景 个人项目、快速实验 团队共享、跨项目复用
命令格式 /hello /plugin-name:hello
版本管理 语义化版本控制
分发方式 手动复制 通过市场安装

一个实际的例子:你在项目里写了一个 /review 命令来做代码审查,用着挺好。后来团队其他人也想用,你把它做成插件,大家通过市场一键安装,命令变成 /code-tools:review。这样不同插件之间也不会冲突。

我的建议是——先在 .claude/ 里实验,等功能稳定了再转成插件。

准备工作

开始之前,确认两件事:

  1. Claude Code 已安装并登录——如果还没装,先参考官方的快速入门指南
  2. 版本号 >= 1.0.33——在终端运行 claude --version 检查一下

如果版本过低,升级到最新版即可。

第一步:创建插件目录和清单

每个插件就是一个文件夹,里面必须有一个 .claude-plugin/plugin.json 文件作为"身份证"。我们来创建一个叫 my-first-plugin 的插件:

bash
# 创建插件主目录和清单目录
mkdir -p my-first-plugin/.claude-plugin

然后在 my-first-plugin/.claude-plugin/plugin.json 里写入以下内容:

json
{
  "name": "my-first-plugin",
  "description": "我的第一个 Claude Code 插件,用来学习插件开发的基础知识",
  "version": "1.0.0",
  "author": {
    "name": "你的名字"
  }
}

这几个字段分别代表:

  • name:插件的唯一标识符,同时也是你的技能命令的前缀。比如这里设为 my-first-plugin,那你后面创建的技能命令就会是 /my-first-plugin:xxx 的格式
  • description:在插件管理器里展示的简介
  • version:遵循语义化版本规范(主版本.次版本.补丁版本)
  • author:可选字段,标注作者信息

到这一步,插件的"骨架"就搭好了。

第二步:添加一个 Skill(技能)

技能是插件最核心的功能单元。你可以把它理解为"给 Claude 写的操作手册"——告诉 Claude 在什么场景下该怎么做。

创建一个简单的问候技能

在插件根目录下创建 skills/hello/ 目录,然后在里面放一个 SKILL.md 文件:

bash
mkdir -p my-first-plugin/skills/hello

my-first-plugin/skills/hello/SKILL.md 的内容:

markdown
---
name: hello
description: 用一条友好的消息问候用户
disable-model-invocation: true
---

用热情友好的方式问候用户,并询问今天有什么可以帮忙的。

文件分两部分:

  1. YAML 前置元数据(两个 --- 之间的部分):定义技能的元信息
  2. Markdown 正文:Claude 在执行这个技能时会遵循的具体指令

前置元数据里几个关键字段说明一下:

字段 作用
name 技能名称,省略则使用目录名
description 告诉 Claude 这个技能干什么、什么时候用
disable-model-invocation 设为 true 表示只能手动触发,Claude 不会自动调用
allowed-tools 限制该技能可以使用的工具,比如 Read, Grep, Glob
context 设为 fork 可在独立的子代理中运行

让技能支持参数

固定的问候没什么意思,我们来让它接受用户输入。修改 SKILL.md

markdown
---
name: hello
description: 用个性化的消息问候用户
---

# 问候命令

用热情友好的方式问候名为 "$ARGUMENTS" 的用户,并询问今天有什么可以帮忙的。让问候语个性化且鼓舞人心。

$ARGUMENTS 是一个特殊占位符,它会捕获用户在技能名称后面输入的所有文本。比如你运行 /my-first-plugin:hello 小明,Claude 收到的就是"用热情友好的方式问候名为 小明 的用户……"

如果技能内容里没写 $ARGUMENTS,Claude Code 会自动把参数追加到内容末尾,所以你的输入不会丢失。

一个更实用的例子:代码审查技能

问候技能只是个入门演示。来看一个实际场景——代码审查:

bash
mkdir -p my-first-plugin/skills/code-review

my-first-plugin/skills/code-review/SKILL.md

markdown
---
name: code-review
description: 按照最佳实践审查代码,检查潜在问题。在审查代码、检查 PR 或分析代码质量时使用。
---

审查代码时,请依次检查以下方面:

1. **代码组织和结构** —— 模块划分是否合理,命名是否清晰
2. **错误处理** —— 是否覆盖了异常场景,错误信息是否有帮助
3. **安全隐患** —— 是否存在注入、XSS、敏感信息泄露等问题
4. **测试覆盖** —— 关键逻辑是否有对应的测试用例
5. **性能考量** —— 是否存在不必要的循环、内存泄漏等问题

输出格式:
- 用表格列出发现的问题,包含"位置"、"问题描述"、"严重程度"、"修复建议"四列
- 最后给出总体评价和改进优先级

注意这里没有设置 disable-model-invocation: true,这意味着当你在对话中聊到代码质量相关的话题时,Claude 可能会自动调用这个技能。如果你只想手动触发,记得加上那个配置。

第三步:给插件加上 Hook(钩子)

Hook 是在特定事件发生时自动执行的脚本。比如"每次 Claude 写入文件后自动跑一次格式化",或者"在提交代码前自动检查是否有敏感信息"。

Hook 的基本概念

Claude Code 支持多种 Hook 事件:

事件名称 触发时机 典型用途
PreToolUse 工具调用前 验证参数、拦截危险操作
PostToolUse 工具调用后 自动格式化、运行 lint
UserPromptSubmit 用户提交提示时 添加上下文、验证输入
Stop Claude 完成响应时 检查任务是否真的完成了
SessionStart 会话开始时 加载环境变量、初始化配置

在插件中配置 Hook

在插件根目录创建 hooks/hooks.json

bash
mkdir -p my-first-plugin/hooks

下面是一个实用的例子——每当 Claude 写入或编辑文件后,自动运行项目的 lint 检查:

json
{
  "description": "自动代码格式化和 lint 检查",
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx eslint --fix 2>/dev/null || true",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

这段配置的含义是:

  1. matcher "Write|Edit" 表示只在写入或编辑文件的操作后触发(支持正则表达式)
  2. Hook 通过 stdin 接收 JSON 格式的输入,用 jq 提取出文件路径
  3. 然后对该文件运行 ESLint 自动修复
  4. timeout 设为 30 秒,防止卡死

Hook 的执行结果通过退出代码来传达:

  • 退出代码 0:成功,继续执行
  • 退出代码 2:阻止操作(对于 PreToolUse 会阻止工具调用)
  • 其他退出代码:非阻止性错误,记录日志后继续

一个更高级的 Hook:防止提交敏感信息

创建一个脚本文件 my-first-plugin/hooks/check-secrets.sh

bash
#!/bin/bash
# 检查文件中是否包含敏感信息

FILE_PATH=$(jq -r '.tool_input.file_path' < /dev/stdin)

# 检查是否是敏感文件
if echo "$FILE_PATH" | grep -qE '\.(env|pem|key)$'; then
    echo "不允许写入敏感文件: $FILE_PATH" >&2
    exit 2
fi

# 检查文件内容是否包含疑似密钥
if echo "$FILE_PATH" | xargs grep -qE '(api_key|secret|password)\s*=' 2>/dev/null; then
    echo "文件中检测到疑似敏感信息,请检查: $FILE_PATH" >&2
    exit 2
fi

exit 0

别忘了给脚本加执行权限:

bash
chmod +x my-first-plugin/hooks/check-secrets.sh

然后在 hooks.json 中引用它:

json
{
  "description": "安全检查和代码格式化",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/check-secrets.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx eslint --fix 2>/dev/null || true",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

注意这里用了 ${CLAUDE_PLUGIN_ROOT} 环境变量来引用插件目录下的脚本,这样不管用户把插件装在哪个位置都能正确找到文件。

第四步:了解完整的插件目录结构

到这里,你的插件目录应该长这样:

text

一个插件还可以包含更多组件:

目录/文件 位置 说明
.claude-plugin/ 插件根目录 只放 plugin.json
skills/ 插件根目录 技能目录,每个子目录是一个技能
commands/ 插件根目录 斜杠命令(与 skills 功能类似)
agents/ 插件根目录 自定义代理定义
hooks/ 插件根目录 Hook 配置和脚本
.mcp.json 插件根目录 MCP Server 配置
.lsp.json 插件根目录 LSP Server 配置

有一个常见错误要特别注意:不要把 skills/hooks/agents/ 这些目录放到 .claude-plugin/ 里面.claude-plugin/ 里只应该有 plugin.json,其他目录都放在插件根目录。

第五步:本地测试

开发阶段不需要正式安装,用 --plugin-dir 参数就能直接加载本地插件进行测试:

bash
claude --plugin-dir ./my-first-plugin

启动后,试试这些操作:

  1. 运行技能命令:输入 /my-first-plugin:hello 你的名字
  2. 查看帮助:输入 /help,确认你的命令出现在插件命名空间下
  3. 测试 Hook:让 Claude 写一个文件,观察 lint 是否自动运行

如果你同时在开发多个插件,可以加载多个目录:

bash
claude --plugin-dir ./plugin-one --plugin-dir ./plugin-two

每次修改插件文件后,需要重启 Claude Code 才能生效。

排查常见问题

如果插件没有按预期工作,按这个顺序检查:

  1. 目录结构是否正确——最常见的问题是把目录放错了位置
  2. plugin.json 语法是否正确——JSON 格式错误会导致插件加载失败
  3. SKILL.md 的前置元数据格式——确保 YAML 语法正确,--- 分隔符不要漏
  4. Hook 脚本权限——确认 .sh 文件有执行权限
  5. 使用调试模式——运行 claude --debug 可以看到 Hook 执行的详细日志

把现有配置迁移成插件

如果你已经在 .claude/ 目录里积累了一些好用的配置,迁移到插件格式很简单:

bash
# 1. 创建插件结构
mkdir -p my-plugin/.claude-plugin

# 2. 写入清单文件
cat > my-plugin/.claude-plugin/plugin.json << 'EOF'
{
  "name": "my-plugin",
  "description": "从独立配置迁移而来",
  "version": "1.0.0"
}
EOF

# 3. 复制现有文件
cp -r .claude/commands my-plugin/    # 复制命令
cp -r .claude/skills my-plugin/      # 复制技能(如果有的话)

# 4. 迁移 Hook(如果有的话)
mkdir -p my-plugin/hooks
# 把 settings.json 中的 hooks 配置提取到 my-plugin/hooks/hooks.json

# 5. 测试
claude --plugin-dir ./my-plugin

迁移完成后,可以把 .claude/ 里的原始文件删掉,避免重复。加载时插件版本会优先于散装配置。

分享你的插件

当你的插件开发测试完毕,可以通过以下步骤分享给其他人:

  1. 添加文档:写一个 README.md 说明安装和使用方法
  2. 版本管理:在 plugin.json 中更新版本号
  3. 发布到市场:通过 Claude Code 的插件市场进行分发
  4. 内部测试:先让团队成员试用,收集反馈后再大范围发布

其他人安装你的插件后,通过 /plugin install 命令即可一键安装使用。

写在最后

Claude Code 的插件系统给了开发者很大的自由度。通过 Skill,你可以教 Claude 按照你团队的规范来工作;通过 Hook,你可以在 Claude 的每一步操作前后插入自动化检查。这些能力组合起来,能把 Claude Code 打造成一个真正符合你工作流的开发助手。

如果你想深入了解更多高级功能,可以参考以下官方文档:

感谢阅读,如果觉得有用欢迎分享