ClaudeClaude Code系列第 15 / 15 篇

Claude Code 插件速查:清单字段、市场文件、加载规则和 claude plugin 命令,附实测输出

写插件和查插件问题时要翻的东西放在一页:清单的字段和路径规则、市场文件、插件从哪里加载、版本怎么算、claude plugin 的每个命令、三条发布的路。校验报什么错、命令输出什么,是本站在服务器上跑出来的。

发布 · 约 35 分钟读完 · 经人工审核()· 本站的内容怎么来的

本站已实测,测试日期:2026-10-13。

本页目录(10 节)
  1. 一、清单 plugin.json
  2. 二、校验 claude plugin validate
  3. 三、市场文件 marketplace.json
  4. 四、插件从哪里来、放在哪里
  5. 五、版本怎么算、什么时候更新
  6. 六、claude plugin 命令
  7. 七、发布:三条路(整理自文档,没有实测)
  8. 通过中转站用,有什么不一样
  9. 这一趟花了多少
  10. 这次实测没有覆盖到的

这篇是一页速查,解决四个问题:清单里能写什么、市场文件怎么写、插件到底是从哪里加载的、claude plugin 的每个命令做什么。

怎么从零做一个插件,看《做一个 Claude Code 插件》;装别人的插件之前怎么审,看《插件进阶(上)》;评测、依赖和托管市场,看《插件进阶(下)》。这一篇不重复那些步骤,只放查得到的规则和实测的输出。

实测环境
日期 2026-10-13
版本 Claude Code 2.1.296,Linux 服务器
做法 两个示例插件放在一个本地市场里;12 份用来校验的清单(11 份各有一处问题)和 2 个写错的市场文件;把 claude plugin 的命令逐个跑一遍,记下输出和退出码

先说实测的结论:

  • 文中标了“实测”的输出和退出码,都是这次在服务器上跑出来的。第七节(发布)整理自文档,没有实测。
  • 清单里的 commands 会替换默认的 commands/ 目录,skills 是追加。实测两种都和文档一致,前一种还会在 claude plugin list 里留一行提示。
  • 从本地目录登记的市场,插件是原地加载的:改了源文件,不用更新就生效。清单里写了版本号的,版本号要等跑了 claude plugin update 才变。
  • 市场文件用了官方的保留名,claude plugin validate 没有报错,登记的时候才被拒绝。
  • 这些命令都在本地执行,不调用模型。这一趟只有两次用来看“会话里加载了哪一份”的请求花了钱,合计约 0.26 美元。

一、清单 plugin.json

可以不写

清单不是必须的。没有它,Claude Code 按标准目录找组件,插件的名字取自市场条目,用 --plugin-dir 加载时取目录名。

要写清单的情况有四种:要填名称、作者这些信息;组件不在默认目录;要让用户填配置(userConfig);要把组件直接写在清单里。

清单放在插件根目录的 .claude-plugin/plugin.json。其他文件都放在插件根目录,不放进 .claude-plugin/。

标准目录

组件 默认位置 说明
清单 .claude-plugin/plugin.json 可选
Skill skills/ 每个 skill 一个 <名字>/SKILL.md
命令 commands/ 平铺的 Markdown 文件。新插件建议用 skills/
子代理 agents/ Markdown 文件,子目录算进名字
Hook hooks/hooks.json
MCP 服务器 .mcp.json
语言服务器 .lsp.json
输出风格 output-styles/
工作流 workflows/ .js 文件
主题 themes/ JSON 文件
监视器 monitors/monitors.json
可执行文件 bin/ 插件启用时,这里的文件在 Bash 工具的 PATH 上
设置 settings.json 只有 agent 和 subagentStatusLine 两项生效

插件根目录的 CLAUDE.md 不会被当成上下文加载。实测校验时会给一条警告:

⚠ Found 1 warning:

  ❯ root: CLAUDE.md at the plugin root is not loaded as project context. To ship context with your plugin, use a skill (skills/<name>/SKILL.md) instead.

✔ Validation passed with warnings

要让一段说明进上下文,写成 skill。

字段

只有 name 是必填的。

字段 类型 说明
name 字符串 插件的标识,必填。所有组件都挂在它下面,比如 deploy-tools:reviewer
displayName 字符串 界面上显示的名字,可以有空格
version 字符串 版本号。写了它,用户就停在这个版本,直到你改它(见第五节)
description 字符串 一句话说明
author 对象 name 必填,email、url 可选
homepage 字符串 文档网址。必须是合法的网址,否则插件加载失败
repository 字符串 仓库网址,不校验
license 字符串 比如 MIT
keywords 字符串数组 检索用的标签
metadata 对象 放自己的数据,Claude Code 不读
defaultEnabled 布尔 用户没设置时是否默认启用,默认 true
dependencies 数组 依赖的插件
settings 对象 只有 agent 和 subagentStatusLine 生效
userConfig 对象 启用时让用户填的配置
channels 数组 插件提供的消息通道,各自绑定一个 MCP 服务器
types 路径 mod 的类型声明文件
skills 路径或数组 另外要扫描的 skill 目录。追加到默认目录
commands 路径、数组或对象 命令文件或目录。替换默认目录
agents 路径或数组 子代理的 .md 文件,不接受目录。替换默认目录
hooks 路径、对象或数组 和 hooks/hooks.json 合并
mcpServers 路径、对象或数组 和 .mcp.json 合并,同名的后者覆盖前者
lspServers 路径、对象或数组 和 .lsp.json 合并
outputStyles 路径或数组 替换默认目录
workflows 路径或数组 替换默认目录
experimental 对象 放 themes、monitors、evals,写法还可能变

另外有五个字段只给 Anthropic 的目录用(icon、documentationUrl、supportUrl、privacyPolicyUrl、termsOfServiceUrl),Claude Code 加载时不读。

名字的规则

名字不能为空,不能有空格、@、:、路径分隔符,建议全小写加连字符。还不能看起来像 Anthropic 自己的插件。实测三种写法:

清单里的 name 实测结果 退出码
Deploy Helper 报错:Plugin name cannot contain spaces. Use kebab-case 1
deployHelper 警告:不是小写加连字符。Claude Code 能用,同步到 claude.ai 的市场要求这种写法 0
claude-deploy 报错:名字是保留的 1

第三种的报错原文:

  ❯ name: Plugin name "claude-deploy" is reserved: it passes as one of Anthropic's own. A third party's plugin name cannot start with "claude-", "anthropic-", "anthropics-", or "cc-plugin-", be "claude", "anthropic", "anthropics", "claude-code", or "claude-mods", or put "official" beside "claude" or "anthropic".

claude plugin init 也拒绝这类名字,实测 claude plugin init claude-helper 直接退出,退出码 1。文档说,名字里别的位置出现 claude 或 anthropic 整个词(比如 mcp-for-claude)是警告,不是报错;这种没有测。

路径的规则

清单里的组件路径相对插件根目录,有三条规则。实测各写错一次:

规则 写错的例子 实测的报错
以 ./ 开头 "commands": "extra-cmds" commands: Invalid input
不能跑出插件目录 "skills": "../ok/skills" Path contains ".." which could be a path traversal attempt
路径要存在 "agents": ["./agents/nobody.md"] Path not found: ./agents/nobody.md

三种都是 Validation failed,退出码 1。第一种的报错只有 Invalid input 两个词,没有说原因。看到它,先检查路径是不是少了 ./。

两个例外:skills 可以写 ".",表示插件根目录;mcpServers 可以写 https:// 开头的包地址。

文档还提到一条:在 macOS 和 Linux 上,路径里有反斜杠的组件不加载,路径一律用正斜杠。这条没有测。

清单里的键和默认目录怎么合并

这是最容易弄错的地方。三类键的行为不一样:

行为 哪些键
替换默认位置 commands、agents、outputStyles、workflows、experimental.themes、experimental.monitors
追加到默认位置 skills
和默认文件合并 hooks、mcpServers、lspServers

实测替换。 一个插件,commands/ 里有 a.md,另一个目录 extra-cmds/ 里有 b.md,清单写 "commands": "./extra-cmds/":

Component inventory
  Skills (2)  b, hello

只有 b,没有 a。claude plugin list 在这个插件下面多一行:

    Note: Default commands/ folder is ignored because the manifest sets "commands"

要两个都留,把默认目录也写进去:"commands": ["./commands/", "./extra-cmds/"]。

实测追加。 另一个插件,skills/ 里有 hello,more-skills/ 里有 extra,清单写 "skills": "./more-skills/":

Component inventory
  Skills (2)  extra, hello

两个都在。

不认识的字段

写在哪里 结果
清单顶层 字段被去掉,插件照常加载。校验给警告
userConfig 的选项、channels 的条目、lspServers 的配置、monitors 的条目里面 报错,插件不加载

实测顶层多写一个 "colour": "red":

⚠ Found 1 warning:

  ❯ colour: Unknown field 'colour'. Claude Code ignores it at load time.

✔ Validation passed with warnings

实测在 userConfig 的一个选项里多写 "secret": true(正确的键是 sensitive):

✘ Found 1 error:

  ❯ userConfig.token: Unrecognized key: "secret"

✘ Validation failed

顶层写错字不会报错,只是悄悄不生效,所以发布前要跑校验。

用户配置 userConfig

声明之后,启用插件时 Claude Code 会让用户填这些值,用户不用自己去改设置文件。键只能用字母、数字和下划线,不能以数字开头。

字段 必填 说明
type 是 string、number、boolean、directory、file 之一
title 是 对话框里的标签
description 是 标签下面的说明
required 否 true 时不接受空值
default 否 用户没填时用的值
options 否 只对 string:限定可选的值
multiple 否 只对 string:允许填多个
sensitive 否 true 时输入打码,值存进系统的凭据库,不进设置文件
min / max 否 只对 number

示例插件里声明了两个:

"userConfig": {
  "api_url": { "type": "string", "title": "API 地址", "description": "发布接口的地址" },
  "channel": {
    "type": "string", "title": "发布通道", "description": "发到哪个通道",
    "options": ["stable", "beta"], "default": "stable"
  }
}

实测安装时会提醒还有选项没填:

2 userConfig options not yet set — run /plugin configure deploy-helper@h32-market in Claude Code, or pass --config KEY=VALUE.

怎么在命令行里填,见第六节的 configure。实测填完之后,不敏感的值存在用户设置文件的 pluginConfigs 下面:

"pluginConfigs": {
  "deploy-helper@h32-market": {
    "options": { "api_url": "https://deploy.example.test", "channel": "beta" }
  }
}

插件里引用这些值有两种写法(整理自文档,没有实测):

  • ${user_config.KEY}:用在 MCP 服务器配置、语言服务器配置、hook 的 args,以及 skill 和子代理的正文里。正文里只替换不敏感的值。
  • 环境变量 CLAUDE_PLUGIN_OPTION_<KEY>:每个选项都会传给 hook 进程,<KEY> 是大写。

写成一整条 shell 命令的 hook、监视器的命令、MCP 的 headersHelper 里不能用 ${user_config.*},用了会直接报错。

三个路径变量

变量 指向 用来放什么
${CLAUDE_PLUGIN_ROOT} 插件当前这个版本的目录 随插件带的脚本、可执行文件、配置
${CLAUDE_PLUGIN_DATA} ~/.claude/plugins/data/<编号>/ 装好的依赖、生成的文件、缓存。更新时保留
${CLAUDE_PROJECT_DIR} 项目根目录 项目里的脚本和配置

${CLAUDE_PLUGIN_ROOT} 每次更新都会变,不要往里面写要长期留着的东西。

这些变量在 hook 命令、MCP 和语言服务器的配置、skill 和子代理的正文里会被替换。Claude 用 Bash 工具执行的命令里没有这几个环境变量,要用就写在 skill 的正文里,让 Claude Code 加载时替换成实际路径。

二、校验 claude plugin validate

校验是检查清单的权威办法。给它一个目录或一个清单文件:

claude plugin validate ./my-plugin

三种结论

结论 退出码 意思
Validation passed 0 清单能加载
Validation passed with warnings 0 能加载,但有该改的地方
Validation failed 1 有错误,加载时也会失败

加 --strict,警告也算失败。实测没写版本号的清单:

⚠ Found 1 warning:

  ❯ version: No version specified. Consider adding a version following semver (e.g., "1.0.0")

✘ Validation failed (--strict treats warnings as errors)

退出码 1。放进 CI 的时候用 --strict。如果是故意不写版本号(见第五节),就不要加。

文档里还有退出码 2,表示校验器自己出了问题。实测给一个不存在的路径,得到的是 File not found 和 Validation failed,退出码是 1,不是 2。

这次实测的 12 份清单

清单里的问题 结论 退出码
没有问题 passed 0
顶层多了不认识的字段 passed with warnings 0
名字不是小写加连字符 passed with warnings 0
没写 version passed with warnings 0
根目录放了 CLAUDE.md passed with warnings 0
名字有空格 failed 1
名字用了保留的前缀 failed 1
路径没有以 ./ 开头 failed 1
路径带 .. failed 1
路径不存在 failed 1
homepage 不是网址 failed 1
userConfig 的选项里有不认识的键 failed 1

给一个目录,它校验什么

  • 有 .claude-plugin/marketplace.json,校验市场。
  • 否则有 .claude-plugin/plugin.json,校验插件。
  • 两个都有,两样都校验。
  • 都没有,按目录名去找 skills、agents、commands 里的文件。

在市场目录上跑,不会打开各个插件自己的 skill、子代理和 hook 文件。要查那些,对每个插件目录单独跑一次。

--json

实测输出是一个对象,顶层有这些键:

{
  "success": true,
  "strict": false,
  "target": "/home/ccdemo/demo/h32-plugins/cases/unknown-field/.claude-plugin/plugin.json",
  "manifest": {
    "file": "…/plugin.json",
    "type": "plugin",
    "errors": [],
    "warnings": [
      { "path": "colour", "message": "Unknown field 'colour'. Claude Code ignores it at load time.", "code": null }
    ],
    "notes": [],
    "gatingHooks": []
  },
  "contents": [],
  "advice": []
}

success 和退出码是同一个结论。contents 是每个组件文件各自的结果。

三、市场文件 marketplace.json

市场文件放在市场目录的 .claude-plugin/marketplace.json。.claude-plugin/ 所在的那一层叫市场的根目录,插件的相对路径从根目录算起,不是从 .claude-plugin/ 算起。

这次用的市场文件:

{
  "name": "h32-market",
  "owner": { "name": "chundu demo" },
  "description": "H32 实测用的本地市场",
  "plugins": [
    { "name": "deploy-helper", "source": "./plugins/deploy-helper", "description": "发布前的检查清单" },
    { "name": "notes-kit", "source": "./plugins/notes-kit", "description": "记笔记的 skill" }
  ]
}

顶层字段

name、owner、plugins 必填。

字段 说明
name 市场的标识:字母、数字、.、_、-,以字母或数字开头
owner 维护人。name 必填
plugins 插件条目的数组。每条单独校验,一条写错不影响别的
description 给用户看的说明,缺了校验会警告
version 市场文件自己的版本
metadata.pluginRoot 只写名字的插件来源从哪个目录找
forceRemoveDeletedPlugins true 时,从 plugins 里删掉的插件会在用户机器上被卸载
allowCrossMarketplaceDependenciesOn 允许从哪些别的市场装依赖
renames 插件改名或下架的对照表

条目的字段

name 和 source 必填。条目里还可以写清单里的大部分字段。

字段 说明
name 用户安装时写在 @ 前面的名字,可以和插件清单里的 name 不同
source 从哪里取这个插件,见下面的来源表
description 显示在插件列表和详情里
version 版本号。清单里也写了的话,以清单为准,校验会警告
category、tags 分类和检索用
strict 默认 true,见下面
defaultEnabled 条目里的值优先于清单里的
displayName 界面上显示的名字,条目里的优先

条目的名字和清单的名字是两回事。 条目的名字用来安装和启用,写在 enabledPlugins 里,缓存目录也按它命名。清单的名字是组件的前缀,重名比较的也是它。两个最好写成一样。

七种来源

类型 字段 说明
相对路径 字符串本身 市场里的一个目录,以 ./ 开头
github repo、ref、sha GitHub 仓库,写成 owner/repo
url url、ref、sha 任意 git 仓库
git-subdir url、path、ref、sha 别的仓库里的一个子目录
npm package、version、registry npm 包,解包时不跑安装脚本
archive url、sha256 HTTPS 上的 zip 包
command command、timeout、mode 在用户机器上跑一条命令,由它输出插件目录

插件在市场仓库里面,用相对路径;在别的仓库的子目录里,用 git-subdir。

相对路径要 Claude Code 手里有市场的整套文件才找得到。市场是用一个直接指向 marketplace.json 的网址登记的,就只取到这一个文件,相对路径找不到,这时每个插件要写成对象形式的来源。

ref 是分支或标签,sha 是 40 位的完整提交号。两个都写,取 sha。

strict

插件自己有 plugin.json,条目里又写了组件字段(commands、agents、skills、hooks、outputStyles、themes)时,由它决定怎么办:

strict 插件有没有 plugin.json 条目写了组件字段 结果
任意 没有 任意 条目就是清单
true(默认) 有 任意 以 plugin.json 为准,条目的组件字段追加进去
false 有 没写 以 plugin.json 为准
false 有 写了 冲突,插件加载失败

保留的名字

市场不能叫官方市场的名字(claude-plugins-official、claude-code-plugins、claude-community、anthropic-marketplace 等),不能叫看起来像官方的名字,也不能叫 inline、builtin、skills-dir、synced、npm、pip、github 这些。以 claudeai- 开头的名字留给 claude.ai 上托管的市场。

实测有一处要留意。 本站建了一个名字叫 claude-plugins-official 的本地市场,校验放过了它:

⚠ Found 2 warnings:

  ❯ plugins: Marketplace has no plugins defined
  ❯ description: No marketplace description provided. Adding a description helps users understand what this marketplace offers

✔ Validation passed with warnings

登记的时候才被拒绝,退出码 1:

✘ Failed to add marketplace: The name 'claude-plugins-official' is reserved for official Anthropic marketplaces and can only be used with GitHub sources from the 'anthropics' organization.

所以市场的名字校验通过了,还要真的登记一次才算数。

写错的市场文件报什么

实测一个有四处错的市场文件:来源没有以 ./ 开头、来源带 ..、github 来源缺了 repo、顶层多了不认识的字段。

✘ Found 4 errors:

  ❯ plugins[1].source: Path contains "..": ../b. Plugin source paths are resolved relative to the marketplace root (the directory containing .claude-plugin/), not relative to marketplace.json. Use "./b" instead of "../b".
  ❯ plugins.0.source: Invalid string: must start with "./"
  ❯ plugins.1.source: Invalid string: must start with "./"
  ❯ plugins.2.source: Invalid input

⚠ Found 1 warning:

  ❯ colour: Unknown field 'colour'. Claude Code ignores it at load time.

✘ Validation failed

报错按条目的序号指位置,从 0 数起。Invalid input 表示来源对不上任何一种类型,常见的是类型名写错,或者少了必填的字段。

这个文件里还有两个条目同名。文档说会报 Duplicate plugin name,这次的输出里没有出现这一条,可能是前面的错误先拦住了,没有再单独测。

四、插件从哪里来、放在哪里

编号的后缀

每个插件有一个 <名字>@<来历> 形式的编号。@ 后面说明它是怎么来的:

后缀 怎么来的 怎么开关
@<市场名> 从登记过的市场安装的 设置文件 enabledPlugins 里写 true 或 false
@inline 用 --plugin-dir、--plugin-url 启动,或者 Agent SDK 传了 plugins 只在这一次会话里生效
@skills-dir 目录放在 ~/.claude/skills/ 或项目的 .claude/skills/ 下面,里面有清单 看清单的 defaultEnabled,设置文件可以覆盖
@synced 在 claude.ai 账号上启用,Claude Code 同步下来的 默认启用,设置文件可以关

三个阶段

设置里写了一个插件,到它真的能用,中间有三步。插件表现得和设置对不上的时候,看它走到了哪一步:

  1. 声明:设置文件里的 enabledPlugins 说哪些插件该启用,extraKnownMarketplaces 说该有哪些市场。
  2. 取到磁盘:~/.claude/plugins/ 下面记着取到了什么,文件也在这里。
  3. 加载进会话:启动时或者上一次 /reload-plugins 时加载的那一套。设置和磁盘上的改动要重新加载或者开新会话才进得来。

实测登记一个本地市场之后,三处都能看到它。用户设置文件里:

"extraKnownMarketplaces": {
  "h32-market": {
    "source": { "source": "directory", "path": "/home/ccdemo/demo/h32-plugins/market" }
  }
}

~/.claude/plugins/ 下面的 known_marketplaces.json 里:

{
  "source": { "source": "directory", "path": "/home/ccdemo/demo/h32-plugins/market" },
  "installLocation": "/home/ccdemo/demo/h32-plugins/market",
  "lastUpdated": "2026-10-13T10:09:28.397Z"
}

安装插件之后,installed_plugins.json 多一条记录:

"deploy-helper@h32-market": [
  {
    "scope": "user",
    "installPath": "/home/ccdemo/.claude/plugins/cache/h32-market/deploy-helper/1.0.0",
    "version": "1.0.0",
    "installedAt": "2026-10-13T10:09:36.769Z",
    "lastUpdated": "2026-10-13T10:09:36.769Z"
  }
]

磁盘上的位置

都在 ~/.claude/plugins/ 下面:

路径 放的是什么
cache/<市场>/<插件>/<版本>/ 每个安装过的版本一个目录
data/<编号>/ 插件长期保存的数据
marketplaces/<名字>/ 从 GitHub、别的 git 主机或网址取来的市场。本地路径登记的市场不在这里
synced/ 从 claude.ai 账号同步下来的插件
installed_plugins.json 安装记录
known_marketplaces.json 取到过的市场

更新或卸载之后,旧版本的目录里会多一个 .orphaned_at 文件,14 天后由后台清理。实测卸载之后能看到这个文件。

原地加载,还是复制一份

来历 加载方式
--plugin-dir 和 skills 目录里的插件 原地加载,不复制
本地路径登记的市场里,用相对路径的插件 原地加载
其他从市场装的插件 复制到 cache/ 里,加载那份副本

实测原地加载。 装好之后,claude plugin list 显示的是 Read from,后面是源目录:

  ❯ deploy-helper@h32-market
    Version: 1.0.0
    Read from: /home/ccdemo/demo/h32-plugins/market/plugins/deploy-helper
    Scope: user
    Status: ✔ enabled

再装一次,输出里直接说明了这一点:

✔ Plugin "deploy-helper@h32-market" is already installed (scope: user) — it loads in place from /home/ccdemo/demo/h32-plugins/market/plugins/deploy-helper, so edits there take effect at the next session start or /reload-plugins

然后在源目录里加一个 skill,不跑任何更新,直接看详情:

Component inventory
  Skills (3)  deploy-check, rollback, ship

原来是两个,新加的 rollback 已经在里面了。

缓存目录里其实也有一份副本,installed_plugins.json 里记的 installPath 指的就是它。但会话读的是源目录。

复制的那一类有一个限制:插件目录以外的文件不会跟着复制,脚本里去读 ../shared 这样的路径会找不到。

在哪里启用

enabledPlugins 可以写在六个地方。从低到高:

来源 写在哪里 管到谁
--add-dir 用这个参数带进来的目录里的设置文件 只这一次会话,只有 true 有效
用户 ~/.claude/settings.json 你,所有项目
项目 .claude/settings.json 所有克隆这个仓库的人
本地 .claude/settings.local.json 你,只在这个仓库
参数 启动时 --settings 传的值 只这一次会话
托管 托管设置 策略覆盖到的所有人,别的来源盖不过它

按编号逐个合并:每个插件取提到它的、优先级最高的那个来源的值。

实测项目和本地。 在一个项目里装到项目范围:

claude plugin install notes-kit@h32-market --scope project

项目的 .claude/settings.json 多了 "notes-kit@h32-market": true。然后只给自己关掉:

claude plugin disable notes-kit@h32-market --scope local

.claude/settings.local.json 多了一条 false,项目文件里的 true 没有动,claude plugin list 显示 ✘ disabled。这就是“项目给所有人开了,我自己不想要”的做法。

这时再想在用户范围启用,会被拒绝:

✘ Failed to enable plugin "notes-kit@h32-market": Plugin "notes-kit@h32-market" is installed at local scope, not user. Use --scope local or omit --scope to auto-detect.

不写 --scope,它按本地、项目、用户的顺序找第一个提到这个插件的范围。实测不带范围再启用,改的是本地那一条。

还有一处实测:装在项目范围的插件,换到项目外面的目录跑 claude plugin list 也会列出来,状态是 ✘ disabled。

文档里另有一条没有测:项目的 .claude/settings.json 里启用了一个插件,别人克隆下来不会自动把它取到机器上,除非它在市场里用的是相对路径来源。

重名的时候谁加载

几个启用的插件清单里的名字相同时,按这个顺序,前面的赢:

  1. 托管设置里提到的插件
  2. --plugin-dir、--plugin-url 加载的
  3. 从市场安装的
  4. skills 目录里的(~/.claude/skills/ 的赢过项目里的)
  5. 从 claude.ai 同步下来的

实测第 2 条和第 3 条。 市场里装着 deploy-helper 1.1.0,再用 --plugin-dir 带一个清单名字相同、版本写成 9.9.9 的目录启动。claude plugin list 两行都显示,市场那一行仍然是 ✔ enabled:

Installed plugins:

  ❯ deploy-helper@h32-market
    Version: 1.1.0
    Read from: /home/ccdemo/demo/h32-plugins/market/plugins/deploy-helper
    Scope: user
    Status: ✔ enabled

Session-only plugins (--plugin-dir / --plugin-url):

  ❯ deploy-helper@inline
    Version: 9.9.9
    Path: /home/ccdemo/demo/h32-plugins/cases/dup-deploy
    Status: ✔ loaded

会话里实际加载的是哪一份,要看 claude -p 加 --output-format stream-json 输出的第一条初始化信息。它的 plugins 一项里,不带参数时是市场那一份:

{"name": "deploy-helper", "path": "/home/ccdemo/demo/h32-plugins/market/plugins/deploy-helper", "source": "deploy-helper@h32-market", "version": "1.1.0"}

skills 一项里有 deploy-helper:deploy-check 和 deploy-helper:rollback。带了同名的 --plugin-dir 之后,变成本地那一份:

{"name": "deploy-helper", "path": "/home/ccdemo/demo/h32-plugins/cases/dup-deploy", "source": "deploy-helper@inline", "version": "9.9.9"}

skills 里只剩 deploy-helper:hello。市场那一份的 skill 一个都不在了,没有任何提示。claude plugin list 里的 enabled 只反映设置,不代表这一份真的加载了。 本地调试完忘了去掉参数,就会以为市场里的版本有问题。

五、版本怎么算、什么时候更新

版本号从哪里来

Claude Code 给每个装上的插件算一个版本,靠它判断有没有更新。顺序是:

  1. 插件清单里的 version
  2. 市场条目里的 version
  3. 两个都没写,按来源类型定:
来源类型 没写版本号时
github、url、git-subdir 提交号的前 12 位
archive SHA-256 的前 12 位
git 托管的市场里的相对路径 提交号
本地目录,插件和市场都不是 git 仓库 unknown
npm unknown

实测后两行。 notes-kit 的清单没写版本号,市场是一个普通目录,装上之后版本是 unknown。把市场目录做成 git 仓库、提交一次,再更新:

✔ Plugin "notes-kit" updated from unknown to 807912b0afa1 for scope project (/home/ccdemo/demo/h32-plugins/proj). Restart to apply changes.

版本变成了提交号的前 12 位。

写了版本号,就要自己改

清单排在第一位,所以清单里写了 "version": "1.0.0",不管之后推了多少次提交,用户那边算出来的版本都不变,claude plugin update 会说已经是最新。两种做法选一种:

  • 每次发布都改版本号。
  • 清单和条目里都不写,让它跟着提交号走。

实测“版本号不变就不更新”的另一面。 把源目录清单里的版本从 1.0.0 改成 1.1.0,不跑更新,claude plugin list --json 里两个版本对不上:

"version": "1.0.0",
"readFromFolder": "/home/ccdemo/demo/h32-plugins/market/plugins/deploy-helper",
"folderVersion": "1.1.0",

version 是安装时记下的,folderVersion 是源目录里现在写的。跑一次更新才对齐:

Checking for updates for plugin "deploy-helper@h32-market"…
✔ Plugin "deploy-helper" updated from 1.0.0 to 1.1.0 for scope user. Restart to apply changes.

再跑一次:

deploy-helper is already at the latest version (1.1.0).

原地加载的插件内容一直是最新的,只是记录里的版本号要等更新才变。

安装之前会不会先刷新市场

插件名怎么写 用哪个命令 刷新什么
名字@市场 /plugin install 或 claude plugin install 先刷新这个市场,再查
只写名字 /plugin install 只刷新开了自动更新的市场,而且是查不到之后才刷
只写名字 claude plugin install 不刷新,只读缓存的目录

本地路径登记的市场不用刷新。刷新失败时,安装照旧用缓存的目录做,输出里会写 marketplace not refreshed。

自动更新

交互式会话里,发出第一条消息之后,Claude Code 等一段随机的时间(最长十分钟),然后刷新所有开了自动更新的市场,更新从这些市场装的插件。正在跑的会话继续用已经加载的版本,会看到一行提示让你跑 /reload-plugins。

一个市场开不开自动更新,按这个顺序定:

  1. 设置文件里 extraKnownMarketplaces 那一条的 autoUpdate
  2. known_marketplaces.json 里那一条的 autoUpdate(/plugin 的 Marketplaces 页签里的开关写的就是它)
  3. 默认值:Anthropic 的官方市场开,其他都关

自己建的市场默认不自动更新。 团队想让大家自动拿到新版本,要每个人打开开关,或者在设置文件里写上。

设了 DISABLE_AUTOUPDATER=1 这类变量的环境里,整个自动更新都不跑。

六、claude plugin 命令

claude plugins 是同一个命令的别名。这些命令在会话外面跑,不调用模型。

三条通用的规则:

  • 退出码:成功 0,失败 1。validate 和 eval 另有自己的。
  • 插件参数:写名字或者 名字@市场。两个市场有同名插件时写全。configure 只接受写全的。
  • 范围:--scope 取 user、project、local,决定写哪个设置文件。update 还可以写 managed。

一览

命令 做什么 别名
init <名字> 在 ~/.claude/skills/<名字>/ 生成一个新插件 new
install <插件> 从登记过的市场安装 i
uninstall <插件> 从一个范围卸载 remove、rm
enable <插件> 启用
disable [插件] 停用,不卸载。--all 停用全部
update <插件> 更新到市场里的最新版本
list 列出装了什么
details <名字> 看组件清单和大致占多少 token
configure <插件> 看或者填 userConfig 的选项
prune 清掉没有人再依赖的自动安装的依赖 autoremove
eval [目标] 跑评测
eval init [名字] 生成评测用例
tag [路径] 给一次发布打 git 标签
test [目录] 跑 mod 的测试
validate <路径> 校验清单或市场文件
marketplace add <来源> 登记市场
marketplace list 列出登记过的市场
marketplace remove <名字> 取消登记 rm
marketplace update [名字] 刷新一个或全部市场

eval 的用法在《插件进阶(下)》,test 在《mod 的测试和排错》。

init:生成了什么

claude plugin init h32-helper --with skills agents hooks mcp --author ccdemo
✔ Created plugin "h32-helper" at ~/.claude/skills/h32-helper
  It will auto-load next session as h32-helper@skills-dir. Run /reload-plugins to load it now.
  Disable: claude plugin disable h32-helper@skills-dir. Remove: delete the directory.

实测生成了这些文件:

.claude-plugin/plugin.json
.mcp.json
SKILL.md
agents/example.md
hooks-handlers/on-session-start.ts
hooks/hooks.json
skills/example/SKILL.md

清单里已经填了 "version": "0.1.0",作者邮箱取自 git 的设置,还有一行 "skills": ["./"],所以根目录的 SKILL.md 也算一个 skill。生成的内容能通过校验。

有三处要自己改:

  • 各个文件里的 TODO。SKILL.md 的 description 决定 Claude 什么时候用它,要写具体。

  • 生成的 hook 用 bun 运行,hooks/hooks.json 里的命令是下面这一行。用的人机器上没有 bun 就跑不起来,脚本里的注释也提醒可以换成 node 或 python3。

    bun "${CLAUDE_PLUGIN_ROOT}/hooks-handlers/on-session-start.ts"
  • .mcp.json 里是两个占位的服务器,不用就删掉。

--with 可以取 skills、agents、hooks、mcp、lsp、output-style、channel。实测三种失败,退出码都是 1:

情况 输出
目录已经有了 …/.claude-plugin already exists. Use --force to overwrite.
--with 写了不认识的 Unknown --with component "widgets". Valid: skills, agents, hooks, mcp, lsp, output-style, channel
名字是保留的 Invalid plugin name "claude-helper"

这个命令只能生成在 ~/.claude/skills/ 下面,没有换位置的参数。

install 和 uninstall

claude plugin install deploy-helper@h32-market
✔ Successfully installed plugin: deploy-helper@h32-market (scope: user)
参数 说明
-s, --scope 装到哪个范围,默认 user
--config <键=值> 顺手填一个 userConfig 选项,可以重复
--marketplace <来源> 市场还没登记时,先登记再装
--json 最后一行输出一个 JSON 对象
-y, --yes 接受市场声明的安装命令,不再询问

只写名字也能装,实测 claude plugin install notes-kit 找到了 notes-kit@h32-market。

卸载的参数:

参数 说明
-s, --scope 从哪个范围卸,默认 user
--keep-data 留着插件的数据目录
--prune 连带清掉没有人再需要的依赖

从最后一个范围卸载时,插件保存的选项、密钥和数据目录默认一起删。实测带 --keep-data:

{"command":"uninstall","outcome":"ok","plugin":"deploy-helper@h32-market","pluginId":"deploy-helper@h32-market","scope":"user","keptData":true,"message":"Successfully uninstalled plugin: deploy-helper (scope: user)"}

再卸一次,退出码 1:

✘ Failed to uninstall plugin "deploy-helper@h32-market": Plugin "deploy-helper@h32-market" not found in installed plugins

--json 的结果

install、uninstall、update、enable、disable 和三个 marketplace 命令都能加 --json。最后一行是一个对象,command、outcome、message 三项一定有,其余的有才出现。脚本里只解析最后一行,前面可能有别的输出。

实测“已经是这个状态”的情况,退出码是 1,但结果里有专门的标记:

{"command":"enable","outcome":"failed","plugin":"notes-kit@h32-market","message":"Plugin \"notes-kit@h32-market\" is already enabled","failureCode":"already_in_goal_state","alreadyInGoalState":true}

脚本可以看 alreadyInGoalState,把这种情况当成成功。

list

不带参数的输出按来历分组:Installed plugins、Session-only plugins、Skills-directory plugins、Synced from claude.ai。用 --plugin-dir 加载的插件,要把这个参数写在子命令前面才看得到:

claude --plugin-dir ./my-plugin plugin list

--json 输出一个数组。实测一条:

{
  "id": "deploy-helper@h32-market",
  "version": "1.0.0",
  "scope": "user",
  "enabled": true,
  "installPath": "/home/ccdemo/.claude/plugins/cache/h32-market/deploy-helper/1.0.0",
  "readFromFolder": "/home/ccdemo/demo/h32-plugins/market/plugins/deploy-helper",
  "folderVersion": "1.0.0",
  "installedAt": "2026-10-13T10:09:36.769Z",
  "lastUpdated": "2026-10-13T10:09:36.769Z",
  "projectEnabled": false,
  "hasUserConfig": true
}

id、version、scope、enabled、installPath 一定有。加载出错时多 errors,有提醒时多 notes(比如前面那条“默认目录被忽略”)。

加 --available(要和 --json 一起用),输出变成一个对象:installed 是上面那个数组,available 是市场里还没装的插件。实测这台机器上 available 里一共 3565 条,本地市场的一条长这样:

{
  "pluginId": "notes-kit@h32-market",
  "name": "notes-kit",
  "description": "记笔记的 skill",
  "marketplaceName": "h32-market",
  "source": "./plugins/notes-kit"
}

details

claude plugin details deploy-helper
deploy-helper 1.0.0
  Description: 发布前的检查清单
  Source: deploy-helper@h32-market

Component inventory
  Skills (2)  deploy-check, ship
  Agents (0)
  Hooks (1)  SessionStart  (harness-only — no model context cost)
  MCP servers (0)
  LSP servers (0)

Projected token cost
  Always-on:   ~110 tok   added to every session

Per-component (rounded)
  component     always-on  on-invoke
  deploy-check        ~70        ~60
  ship                ~40        ~20

插件要先加载了才能看:装了的、skills 目录里的,或者同一条命令里用 --plugin-dir 带上的。commands/ 里的命令也算在 Skills 那一行里。

configure

不带参数,列出每个选项和填没填,不显示值:

Options for deploy-helper (deploy-helper@h32-market):
  ❯ api_url — API 地址 (optional, not set)
  ❯ channel — 发布通道 (optional, not set)

填值用标准输入传一个 JSON 对象:

echo '{"api_url":"https://deploy.example.test","channel":"beta"}' \
  | claude plugin configure deploy-helper@h32-market --values-stdin
Configuration saved. Restart Claude Code to apply it.

没提到的选项保留原值。实测三种失败,退出码都是 1,而且什么都不保存:

情况 输出
值不在 options 里 Failed to save configuration: 发布通道 must be one of: stable, beta
键没有声明过 This plugin has no option "nope". Known options: api_url, channel.
只写了名字,没写市场 No installed plugin has the id "deploy-helper". Use its full id (name@marketplace)

加 --json 会把选项的定义、已保存的值、填了和没填的键都输出来。这个输出里有保存的值,别贴到公开的地方。

update、prune、tag

update 的输出在第五节。不写 --scope 时,它按本地、项目、用户、托管的顺序找插件装在哪里。

prune 只清自动装上的依赖,不碰你自己装的。实测没有依赖时:

Nothing to prune (no auto-installed plugins at user scope).

不在终端里跑又没加 -y,它只列出来,不删。

tag 给一次发布打一个带说明的 git 标签,名字是 <插件名>--v<版本>。先加 --dry-run 看看:

claude plugin tag plugins/deploy-helper --dry-run
Plugin:  deploy-helper
Version: 1.1.0 (from plugin.json)
Marketplace entry: plugins[0] in /home/ccdemo/demo/h32-plugins/market/.claude-plugin/marketplace.json
Tag:     deploy-helper--v1.1.0

✔ Dry run — would create tag deploy-helper--v1.1.0 at HEAD in /home/ccdemo/demo/h32-plugins/market

去掉 --dry-run 就真的打上,加 --push 顺便推到远端。实测两种失败,退出码 1:

情况 输出
没写版本号 No version to tag. Set "version" in …/plugin.json or in the marketplace entry
标签已经有了 Tag "deploy-helper--v1.1.0" already exists locally. Bump the version in plugin.json, or re-run with --force to move the tag.

第一种的输出里还说明了标签的用处:只有依赖的版本约束用得到它,靠提交号定版本的插件不需要打。

marketplace 的四个命令

add 的参数写法决定了来源类型:

写法 类型 怎么取
owner/repo,可以加 #ref 或 @ref github 克隆 GitHub 仓库
user@host:path git 走 SSH 克隆
以 .git 结尾的网址 git 克隆
github.com 或 gitlab.com 的仓库网址 git 补上 .git 再克隆
其他网址 url 把这个网址当成 marketplace.json 取下来
./路径、/路径、~/路径 指向目录 directory 原地读
同样的写法指向 .json 文件 file 原地读

自建的 git 主机,网址不带 .git 会被当成 url 类型,取不到仓库。要克隆,就在后面加上 .git。

实测四种输入:

输入 输出 退出码
./market(第一次) Successfully added marketplace: h32-market (declared in user settings) 0
./market(第二次) Marketplace 'h32-market' already on disk — declared in user settings 0
market(少了 ./) Invalid marketplace source format. Try: owner/repo, https://..., or ./path 1
名字是保留的 见第三节 1

--scope 决定声明写进哪个设置文件,默认 user。写 project,克隆这个仓库的人也会有这个市场。

list 实测:

  ❯ h32-market
    Source: Folder (/home/ccdemo/demo/h32-plugins/market)

加 --json,每个市场一个对象,有 name、source、installLocation,再按类型带 repo、url 或 path。

remove 的参数是市场的名字,不是登记时写的来源。从最后一个范围移除时,从这个市场装的插件会一起卸掉,它们保存的选项和数据也会删。实测:

✔ Successfully removed marketplace: h32-market
Also uninstalled 1 plugin from this marketplace:
  deploy-helper@h32-market
The removal also deletes their saved options, secrets and data where it can.
To use a plugin again, add the marketplace back and reinstall the plugin.

实测之后,用户设置和项目设置里的 enabledPlugins、pluginConfigs 也都清掉了。只是想刷新,用 update,不要先删再加。

指定的范围里没有声明这个市场时,退出码 1:

✘ Failed to remove marketplace: Marketplace 'h32-market' is not declared in project settings. Omit --scope to remove it from all scopes.

update 不写名字就刷新全部。写了分支或标签的市场,更新到那个分支或标签的最新提交。实测不写名字又加 --json 会被拒绝,退出码 1。

会话里的 /plugin

/plugin 打开插件面板,只能在交互式的终端会话里用。和命令行对得上的几个:

会话里 做什么
/plugin 打开面板的 Discover 页签
/plugin list 直接列出装了的插件,可以加 --enabled 或 --disabled
/plugin install <插件> 打开这个插件的详情,确认之后才装
/plugin manage 打开 Installed 页签
/plugin enable、disable、uninstall 打开 Installed 页签并执行
/plugin configure <插件> 打开配置对话框
/plugin validate <路径> 和命令行的校验一样
/plugin marketplace add [来源] 登记市场

init、update、details、prune、eval、test 没有会话里的写法。

/reload-plugins 把会话外面做的改动应用进来,不用重启。它会输出一行统计:插件、skill、子代理、hook 各多少个。会增减 MCP 服务器的改动可能让提示缓存失效,这时它先不应用,提示你加 --force 再跑一次。

只加载一次的两个参数

参数 说明
--plugin-dir <路径> 从目录或 zip 包加载。给一个放着多个插件的目录,里面每个有清单的子目录都加载
--plugin-url <网址> 从网址取 zip 包

两个都可以重复写,加载的插件编号是 <名字>@inline。它们和已安装的同名插件撞上时谁赢,见第四节。

七、发布:三条路(整理自文档,没有实测)

按谁来装选

方式 谁能装 你要准备什么 用户会不会自动拿到更新
不用市场 拿到插件目录或 zip 包的人 插件目录 不会,他们用的是你给的那一份
自己的市场 够得着那个仓库的人。仓库是私有的,市场也就是私有的 一个带 marketplace.json 的 git 仓库 默认不会
Anthropic 的目录 在 claude.ai 或 Cowork 里添加它的人,也会同步到他们的 Claude Code 一个放着插件的 GitHub 仓库,付费的 claude.ai 套餐 会,在你推的版本发布之后

发布之前检查四样

  1. 名字。 用户按 名字@市场 安装和配置,改了名对已经装的人来说就是另一个插件。定下来就别改。
  2. 版本。 要么每次发布都改,要么不写(见第五节)。
  3. 校验。 claude plugin validate --strict ./your-plugin。
  4. 真的装一次。 登记一个本地市场,从里面装上,开一个会话确认它加载了。

另外把 description、author、homepage、repository 填上,根目录放一个 README.md。

不用市场

对方可以克隆仓库,或者解开你发的 zip 包,然后:

  • 只用一次:claude --plugin-dir ./deploy-helper。
  • 每次都用:把插件目录放到 ~/.claude/skills/ 下面。

要更新,他们得重新拉一次。

自己的市场

在仓库里加一个 .claude-plugin/marketplace.json 就算发布了,不用提交给谁。插件和市场放在同一个仓库时,条目的来源写 "./":

{
  "name": "your-marketplace",
  "owner": { "name": "Your Name" },
  "plugins": [
    { "name": "deploy-helper", "source": "./" }
  ]
}

告诉用户两条命令:

claude plugin marketplace add your-org/your-marketplace
claude plugin install deploy-helper@your-marketplace

也可以合成一条,claude plugin install 加 --marketplace 参数(要 2.1.292 以上)。

提交到 Anthropic 的目录

Anthropic 的目录是 claude.ai 和 Cowork 里的那个目录。在那里上架,claude.ai、Cowork 和 Claude Code 的用户都能拿到。要点:

  • 从 claude.ai 的开发者入口提交,需要付费套餐。Pro 和 Max 用自己的账号;Team 和 Enterprise 由 Owner 提交。
  • 提交前先跑 claude plugin validate ./your-plugin --strict。
  • 有些组件只有 Claude Code 能用,在 claude.ai 和 Cowork 里不加载。有 bin/ 目录的插件,claude.ai 和 Cowork 不装。
  • 上架的插件在 Claude Code 里以 <名字>@synced 的形式加载。
  • 官方市场 claude-plugins-official 不通过这个入口收插件。

通过中转站用 Claude Code 的读者注意: 文档写明,同步只在用 claude.ai 账号登录的会话里进行。用 ANTHROPIC_AUTH_TOKEN 这类变量提供凭据的会话,既不下载也不加载同步的插件。所以在 claude.ai 上启用的插件,不会出现在走中转站的 Claude Code 里,要用就从市场装。

Anthropic 的三个市场

官方 社区 示例
仓库 anthropics/claude-plugins-official anthropics/claude-plugins-community anthropics/claude-code
市场名 claude-plugins-official claude-community claude-code-plugins
里面是什么 Anthropic 维护的,加上合作方和其他作者的 第三方作者提交的 一小组演示用的插件
怎么有的 第一次开交互式会话时自动登记 自己登记 自己登记

三处容易弄混:

  • 社区市场的名字是 claude-community,和仓库名不一样。安装时 @ 后面写的是市场名。
  • 旧教程里的 /plugin marketplace add anthropics/claude-code 登记的是示例市场,不是官方市场。
  • 示例市场里的大部分插件在官方市场里也有,名字相同。从官方市场装,免得装两份。

官方市场里大部分插件来自合作方和其他作者,不是 Anthropic 自己写的。很多常用的插件也不在 Anthropic 的任何一个市场里,而在作者自己的仓库里。Anthropic 不审第三方市场,装之前怎么看,见《插件进阶(上)》的第二节。

实测这台服务器上,claude plugin marketplace list 里除了官方市场,还有一条内置的 anthropic-plugin-directory。

通过中转站用,有什么不一样

  • 这一篇的命令和接口无关。 校验、安装、登记市场都在本地做,不发模型请求,走不走中转站结果一样。
  • 取市场要能连上 GitHub。 官方市场和大多数第三方市场是从 GitHub 克隆的,这一步不经过中转站,网络不通就取不下来。
  • 从 claude.ai 同步的插件用不了,原因见第七节。

这一趟花了多少

除了两次请求,其余命令都不调用模型。那两次是为了看会话里加载的是哪一份插件,各发了一句“只回复 ok”,Claude Code 自己估算的花费是每次约 0.13 美元,合计约 0.26 美元。这是按官方价格估的,实际按中转站的计费。

这次实测没有覆盖到的

  • 只测了本地目录登记的市场。 从 GitHub、网址、npm、zip 包取插件的几种来源,以及 command 来源,都没有测。这些来源的插件是复制到缓存里加载的,和这次看到的原地加载不一样。
  • 自动更新没有测,那一节整理自文档。
  • 从 claude.ai 同步的插件、托管设置、Anthropic 的目录都没有测,实测环境没有 claude.ai 账号。
  • strict 的四种组合、renames、跨市场依赖没有测。
  • 敏感的配置项存到了哪里没有看,只测了不敏感的。
  • 会话里的 /plugin 面板和 /reload-plugins 这次没有操作,表格整理自文档。
  • 有一次没弄清的情况:带着同名的 --plugin-dir 跑 claude plugin details,第一次两分多钟没有输出,结束进程之后重跑是正常的,没有再出现。
  • 只在一个版本上测过。 文档里不少条目标了从哪个版本开始有,旧版本上的表现可能不同。

来源

通过 API 中转站使用这些模型?到 Veridrop 免费检测中转站给你的是不是它声称的模型,或者看看中转站排行榜前 100 名。

相关文章