自定义Plugin开发指南:从零创建Plugin

从零开始开发Claude Code Plugin

一、Plugin开发的准备工作

在开始开发Claude Code Plugin之前,需要做好充分的准备工作。Plugin是Claude Code的扩展模块,通过Plugin API与Claude Code交互,实现自定义命令、工具、钩子等功能。本节将介绍开发环境的搭建和项目初始化。

1.1 了解Plugin框架API

Claude Code Plugin框架提供了一套完整的API,让开发者可以扩展Claude Code的功能。核心API包括:

1.2 安装开发工具

开发Plugin需要Node.js环境和Claude Code CLI。以下是安装步骤:

# 确保已安装 Node.js(建议 v18 以上) node -v # 全局安装 Claude Code CLI npm install -g @anthropic-ai/claude-code # 验证安装 claude --version

1.3 创建Plugin项目

Plugin项目遵循标准的Node.js包结构。创建一个新的项目目录并初始化:

# 创建项目目录 mkdir my-claude-plugin cd my-claude-plugin # 初始化 npm 项目 npm init -y # 安装 Plugin SDK(如需要) npm install @anthropic-ai/claude-plugin-sdk
说明: Plugin项目本质上是一个npm包,需要遵循npm包的命名规范。建议使用 claude-plugin- 前缀命名,方便社区发现。
提示: 在项目根目录创建 src/ 目录管理源码,使用 src/index.js 作为入口文件,有助于保持项目结构清晰。

二、manifest.json完整配置

manifest.json是Plugin的核心配置文件,位于项目根目录。Claude Code通过读取此文件来识别和加载Plugin。下面详细讲解每一个配置项的作用。

2.1 基础配置示例

{ "name": "claude-plugin-my-plugin", "version": "1.0.0", "description": "我的第一个Claude Code Plugin", "main": "src/index.js", "commands": [ { "name": "hello", "description": "打招呼命令", "usage": "/hello [name]" } ], "hooks": { "beforeCommand": ["log-before"], "afterCommand": ["log-after"] }, "permissions": ["read", "write"], "dependencies": {} }

2.2 配置项详解

配置项 类型 必填 说明
name string Plugin名称,建议与npm包名一致
version string 语义化版本号,遵循SemVer规范
description string 简短描述Plugin功能
main string 入口文件路径,相对于项目根目录
commands array 注册的斜杠命令列表,每个命令包含name和description
hooks object 声明生命周期钩子及对应的处理函数名称
permissions array Plugin运行所需的权限声明
dependencies object Plugin内部依赖的其他Plugin

2.3 权限声明

permissions字段用于声明Plugin需要访问的资源权限。Claude Code会在加载Plugin时检查权限声明并提示用户授权。

// 支持的权限类型 "permissions": [ "read", // 读取文件 "write", // 写入文件 "network", // 网络访问 "clipboard", // 剪贴板访问 "terminal", // 终端交互 "environment" // 环境变量访问 ]
注意: 权限声明应遵循最小权限原则,只声明Plugin确实需要的权限。过多的权限声明可能降低用户对Plugin的信任度。

三、核心功能开发

入口文件(如 src/index.js)是Plugin的核心实现。Claude Code在加载Plugin时会调用入口文件的导出函数,并将Plugin上下文(context)作为参数传入。开发者通过context对象访问所有API。

3.1 注册斜杠命令(onCommand)

通过 context.onCommand() 注册自定义斜杠命令。用户在对话中输入 / 后即可看到所有可用命令。

module.exports = function(context) { // 注册 /hello 命令 context.onCommand('hello', async (args) => { const name = args.trim() || 'World'; return `Hello, ${name}! 欢迎使用Claude Code Plugin开发。`; }); // 注册 /weather 命令 context.onCommand('weather', async (args) => { const city = args.trim() || '北京'; // 调用外部API获取天气数据 const response = await fetch( `https://api.weather.com/${city}` ); const data = await response.json(); return `${city}当前气温:${data.temp}°C,天气:${data.condition}`; }); };

3.2 添加文件监听器(onFileChange)

通过 context.onFileChange() 监听文件变化,在文件修改时自动触发逻辑。

module.exports = function(context) { // 监听当前工作区的所有 .md 文件 context.onFileChange('**/*.md', async (eventType, filePath) => { console.log(`[Plugin] 文件变更: ${eventType} - ${filePath}`); if (eventType === 'change') { // 读取文件内容 const content = context.readFile(filePath); // 检查文件是否包含 TODO 标记 if (content.includes('TODO')) { context.showNotification({ title: '待办事项提醒', message: `文件 ${filePath} 中包含未完成的TODO项` }); } } }); };

3.3 注册生命周期钩子

生命周期钩子允许Plugin在特定事件节点执行自定义逻辑。通过 context.onHook() 注册。

module.exports = function(context) { // 在命令执行之前触发 context.onHook('beforeCommand', async (commandName, args) => { console.log(`[Plugin] 即将执行命令: ${commandName}`); return { commandName, args }; }); // 在命令执行之后触发 context.onHook('afterCommand', async (commandName, result) => { console.log(`[Plugin] 命令执行完成: ${commandName}`); context.setGlobalState('lastCommand', commandName); return result; }); // 在读取文件后触发,可修改内容 context.onHook('afterRead', async (filePath, content) => { if (filePath.endsWith('.md')) { return content + '\n\n---\n*由Plugin自动添加*'; } return content; }); };

核心要点: 生命周期钩子必须返回预期的数据结构,否则可能导致Claude Code行为异常。beforeCommand应返回 { commandName, args },afterRead应返回修改后的内容字符串。

3.4 注册上下文菜单动作

通过 context.addContextMenuAction() 在文件的上下文菜单中添加自定义操作。

module.exports = function(context) { // 添加"统计代码行数"菜单项 context.addContextMenuAction({ id: 'count-lines', label: '统计代码行数', when: 'file', action: async (filePath) => { const content = context.readFile(filePath); const lines = content.split('\n').length; const codeLines = content.split('\n') .filter(line => line.trim() !== '').length; return `文件: ${filePath} 总行数: ${lines} 有效代码行数: ${codeLines}`; } }); };

四、Plugin测试和调试

测试和调试是Plugin开发中不可或缺的环节。Claude Code提供了多种方式来验证Plugin的功能是否正确。

4.1 本地加载测试

在开发过程中,可以通过两种方式加载本地Plugin进行测试:

# 方式一:使用 npm link 全局链接 cd my-claude-plugin npm link # 方式二:在 settings.json 中直接指定Plugin路径 // .claude/settings.json { "plugins": [ "file:///Users/username/projects/my-claude-plugin" ] }
推荐: 在开发阶段推荐使用 settings.json 方式加载Plugin,这样可以快速迭代而无需频繁执行 npm link。

4.2 调试输出

使用 console.log 进行调试输出是最直接的调试方式。Claude Code会将插件的控制台输出重定向到日志文件。

module.exports = function(context) { context.onCommand('debug-test', async (args) => { console.log('[DEBUG] 开始执行 debug-test 命令'); console.log('[DEBUG] 接收参数:', args); try { const result = await someAsyncFunction(args); console.log('[DEBUG] 执行成功:', result); return result; } catch (error) { console.error('[DEBUG] 执行失败:', error.message); return `错误: ${error.message}`; } }); };
注意: 发布前务必将调试日志代码移除或通过环境变量控制开启,避免日志过度输出影响性能。

4.3 单元测试编写

编写单元测试确保Plugin各模块功能正确。推荐使用 Jest 测试框架。

// 安装测试依赖 npm install --save-dev jest // tests/plugin.test.js const plugin = require('../src/index'); describe('Plugin命令测试', () => { let mockContext; beforeEach(() => { mockContext = { onCommand: jest.fn(), onFileChange: jest.fn(), onHook: jest.fn(), readFile: jest.fn().mockReturnValue(''), setGlobalState: jest.fn(), getGlobalState: jest.fn().mockReturnValue(null) }; }); test('应该正确注册hello命令', () => { plugin(mockContext); expect(mockContext.onCommand).toHaveBeenCalledWith( 'hello', expect.any(Function) ); }); test('hello命令应返回问候语', async () => { plugin(mockContext); const helloHandler = mockContext.onCommand.mock.calls .find(call => call[0] === 'hello')[1]; const result = await helloHandler('Claude'); expect(result).toBe( 'Hello, Claude! 欢迎使用Claude Code Plugin开发。' ); }); });

4.4 常见问题排查

问题 可能原因 解决方案
Plugin未加载 manifest.json路径或格式错误 检查manifest.json是否在项目根目录,JSON格式是否正确
命令不显示 onCommand未正确注册 确认入口文件是否正确导出函数,onCommand是否被调用
权限不足 permissions声明缺失 在manifest.json中添加相应的权限声明
钩子不触发 钩子名称或签名不匹配 检查钩子名称是否正确,回调函数签名是否符合API要求

五、Plugin发布和维护

完成开发和测试后,可以将Plugin发布到npm或GitHub,供其他用户安装使用。良好的版本管理和文档编写对Plugin的长期维护至关重要。

5.1 发布到npm

Plugin作为npm包发布,用户可以全局安装后直接被Claude Code发现。

# 登录npm账号 npm login # 构建项目(如有构建步骤) npm run build # 发布到npm npm publish # 用户安装 npm install -g claude-plugin-my-plugin # 在settings.json中启用 // .claude/settings.json { "plugins": ["claude-plugin-my-plugin"] }
说明: 发布前请确保 package.json 的 name 与 manifest.json 的 name 保持一致,方便Claude Code自动关联查找。

5.2 GitHub开源和README编写

在GitHub上开源Plugin可以吸引社区贡献者,提升Plugin的质量和功能。建议的README结构:

# claude-plugin-my-plugin ## 简介 简要描述Plugin的功能和使用场景。 ## 安装 ```bash npm install -g claude-plugin-my-plugin ``` ## 配置 在 `.claude/settings.json` 中启用: ```json { "plugins": ["claude-plugin-my-plugin"] } ``` ## 命令列表 - /hello [name] -- 打招呼 - /weather [city] -- 查询天气 ## 权限说明 - read: 读取文件内容 - network: 调用外部API ## 开发 ```bash git clone https://github.com/username/claude-plugin-my-plugin cd claude-plugin-my-plugin npm install ``` ## 许可证 MIT

5.3 版本号管理(SemVer)

遵循语义化版本(SemVer)规范管理Plugin版本:

版本号变更 说明 示例
主版本(MAJOR) 不兼容的API变更 1.0.0 → 2.0.0
次版本(MINOR) 向下兼容的功能新增 1.0.0 → 1.1.0
补丁(PATCH) 向下兼容的问题修复 1.0.0 → 1.0.1

5.4 更新日志和迁移指南

在GitHub仓库中维护 CHANGELOG.md 文件,记录每个版本的变更内容,帮助用户了解升级带来的影响。

# Changelog ## [1.1.0] - 2026-05-08 ### 新增 - 新增 /weather 命令,支持查询城市天气 - 新增文件变化监听功能,自动检测TODO标记 ### 修复 - 修复 /hello 命令中文参数编码问题 - 修复文件监听器在Windows平台路径分隔符错误 ## [1.0.0] - 2026-04-15 ### 新增 - 基础Plugin框架搭建 - /hello 问候命令 - beforeCommand/afterCommand 生命周期钩子 - 上下文菜单"统计代码行数"动作

总结: 开发一个完整的Claude Code Plugin需要经过环境搭建、manifest配置、核心功能编码、测试调试、发布维护五个阶段。遵循标准化流程和最佳实践,可以大幅提高Plugin质量和开发效率。Plugin生态正在快速发展,掌握Plugin开发技能可以极大地扩展Claude Code的能力边界。