首页
/ Codex 插件清单规范详解:plugin.json 与 marketplace.json 的字段、默认值与校验规则

Codex 插件清单规范详解:plugin.json 与 marketplace.json 的字段、默认值与校验规则

2026-09-06 16:00:09作者:魏侃纯Zoe

本篇技术指南围绕 Codex 内置 plugin-creator 技能所遵循的插件清单(plugin.json)与个人/仓库级市场清单(marketplace.json)规范展开。读完之后,你可以独立完成:创建结构合法的 Codex 插件脚手架、填写通过校验的完整清单字段、为插件生成带安装与认证策略的 marketplace 条目,并理解本地迭代时 cachebuster 重装机制背后的版本改写逻辑。

插件清单规范定义在 plugin-json-spec.md 中,配套的脚手架与校验脚本位于 plugin-creator 技能目录 下。该技能是 Codex 用于“创建/更新本地插件”的内置能力,规范文档中明确写道:本仓库的脚手架统一写入 .codex-plugin/plugin.json,将其作为技能生成时清单文件的标准位置。

插件目录结构与脚手架命令

一个合法的插件目录至少包含 .codex-plugin/plugin.json,可选包含 skills/hooks/scripts/assets/.mcp.json.app.jsonSKILL.md 给出的标准脚手架流程如下(命令均在技能根目录下运行):

# 插件名会被规范化为小写连字符格式,且长度必须 <= 64 字符
# 生成的目录名与 plugin.json 的 name 始终一致
# 默认创建在 ~/plugins/<plugin-name>
python3 scripts/create_basic_plugin.py <plugin-name>

需要插件出现在 Codex UI 的顺序列表中时,追加 --with-marketplace;仓库/团队级市场需要显式同时传入 --path--marketplace-path

# 默认写入个人市场 ~/.agents/plugins/marketplace.json
python3 scripts/create_basic_plugin.py my-plugin --with-marketplace

# 仅当默认 personal 市场名已被占用时才用 --marketplace-name
python3 scripts/create_basic_plugin.py my-plugin \
  --with-marketplace \
  --marketplace-name team-local

# 仓库/团队市场(仅在用户明确要求该位置时使用)
python3 scripts/create_basic_plugin.py my-plugin \
  --path <repo-root>/plugins \
  --marketplace-path <repo-root>/.agents/plugins/marketplace.json \
  --with-marketplace

从脚手架脚本 create_basic_plugin.py 的源码可以确认几处文档级默认值:

  • 插件名规范化:My Pluginmy-plugin,下划线、空格、标点统一替换为 -,连续连字符折叠,超过 64 字符直接报错(MAX_PLUGIN_NAME_LENGTH = 64);
  • 新清单固定以 "version": "0.1.0""category": "Productivity"、空 capabilities 数组起步,并自动生成由插件名派生的 displayName
  • --with-mcp / --with-apps 会创建 .mcp.json{"mcpServers": {}})和 .app.json{"apps": {}})占位文件,同时在清单中写入对应的 "mcpServers": "./.mcp.json""apps": "./.app.json" 字段——这正是“伴生文件不存在时清单不得声明该字段”约束的来源;
  • 市场条目的默认策略常量是 DEFAULT_INSTALL_POLICY = "AVAILABLE"DEFAULT_AUTH_POLICY = "ON_INSTALL"

plugin.json 完整字段参考

下面是规范文档给出的完整示例(canonical sample),保留了原始文档的全部字段:

{
  "name": "plugin-name",
  "version": "1.2.0",
  "description": "Brief plugin description",
  "author": {
    "name": "Author Name",
    "email": "author@example.com",
    "url": "https://github.com/author"
  },
  "homepage": "https://docs.example.com/plugin",
  "repository": "https://github.com/author/plugin",
  "license": "MIT",
  "keywords": ["keyword1", "keyword2"],
  "skills": "./skills/",
  "hooks": "./hooks.json",
  "mcpServers": "./.mcp.json",
  "apps": "./.app.json",
  "interface": {
    "displayName": "Plugin Display Name",
    "shortDescription": "Short description for subtitle",
    "longDescription": "Long description for details page",
    "developerName": "OpenAI",
    "category": "Productivity",
    "capabilities": ["Interactive", "Write"],
    "websiteURL": "https://openai.com/",
    "privacyPolicyURL": "https://openai.com/policies/row-privacy-policy/",
    "termsOfServiceURL": "https://openai.com/policies/row-terms-of-use/",
    "defaultPrompt": [
      "Summarize my inbox and draft replies for me.",
      "Find open bugs and turn them into Linear tickets.",
      "Review today's meetings and flag scheduling gaps."
    ],
    "brandColor": "#3B82F6",
    "composerIcon": "./assets/icon.png",
    "logo": "./assets/logo.png",
    "logoDark": "./assets/logo-dark.png",
    "screenshots": [
      "./assets/screenshot1.png",
      "./assets/screenshot2.png",
      "./assets/screenshot3.png"
    ]
  }
}

顶层字段

字段 类型 说明
name string 插件标识符(kebab-case,无空格)。若提供 plugin.json 则必填,并作为清单名与组件命名空间
version string 插件语义化版本(严格 semver,见校验一节)
description string 简短用途摘要
author object 发布者身份:name(作者/团队名)、email(联系邮箱)、url(主页/个人主页 URL)
homepage string 插件使用文档 URL
repository string 源码仓库 URL
license string 许可标识,如 MITApache-2.0
keywords string[] 搜索/发现标签
skills string 指向技能目录/文件的相对路径
hooks string Hook 配置文件路径(注意:见下文的校验限制)
mcpServers string 或 object MCP 配置路径,或直接内联的 MCP server 对象
apps string 插件集成的应用清单路径
interface object 插件展示用的界面/UX 元数据块

mcpServers 的两种声明方式

mcpServers 既可以声明为一个伴生文件路径:

{
  "mcpServers": "./.mcp.json"
}

也可以直接在 plugin.json 内以对象形式声明,键为 MCP server 名,值为 server 配置对象:

{
  "mcpServers": {
    "counter": {
      "type": "http",
      "url": "https://sample.example/counter/mcp"
    }
  }
}

校验脚本 validate_plugin.py 对这两种形态都做了实现级约束:字符串形态必须恰好解析为 .mcp.jsonvalidate_optional_contract_path 要求与默认伴生文件名一致),且对应文件必须存在;对象形态则逐条检查 server 名非空、配置为对象。

interface 字段

字段 类型 说明
displayName string UI 中展示的插件标题
shortDescription string 紧凑视图用的简短副标题
longDescription string 详情页用的长描述
developerName string 人类可读的发布方名称
category string 插件分类
capabilities string[] 来自实现的能力列表
websiteURL string 插件公开网站
privacyPolicyURL string 隐私政策 URL
termsOfServiceURL string 服务条款 URL
defaultPrompt string[] 在 composer/UX 上下文展示的起始提示词,最多 3 条;每条上限 128 字符,超出截断;建议写 50 字符左右的短提示
brandColor string 插件卡片主题色,#RRGGBB 格式
composerIcon string 图标资源路径
logo string 标志资源路径
logoDark string 可选,深色模式下的标志路径
screenshots string[] 截图资源路径列表,必须是存放在 ./assets/ 下的 PNG 文件名,路径相对插件根目录

对照 validate_plugin.py 的实现,可以确认规范文档之外的若干硬性要求:

  • interfacedisplayNameshortDescriptionlongDescriptiondeveloperNamecategory 五个字段全部必填且为非空字符串;
  • defaultPrompt 必填(同时接受 defaultPromptdefault_prompt 键名),且 capabilities 必须是字符串数组;
  • brandColor 用正则 ^#[0-9A-F]{6}$(忽略大小写)校验,不符合即报错;
  • websiteURLprivacyPolicyURLtermsOfServiceURL 若存在,必须是绝对 https:// URL(urlparse 检查 scheme 与 netloc);
  • composerIconlogologoDarkscreenshots 每一项都会解析到磁盘,路径必须留在插件目录内部(拒绝绝对路径和 .. 段)且文件必须真实存在。

路径约定与默认行为

规范文档对路径的约定如下,这些约定在脚手架与校验代码中均得到印证:

  • 路径值应为相对路径且以 ./ 开头;
  • skillshooks 与字符串形态的 mcpServers 是在默认组件发现(default component discovery)之上补充声明,不会替换默认发现逻辑——从源码结构看,这是“显式声明 + 约定目录”双轨并行的设计;
  • 自定义路径值必须遵循插件根目录约定与命名/命名空间规则;
  • 脚手架的清单固定写在 .codex-plugin/plugin.json

一个值得特别注意的矛盾点:规范示例中虽然出现了 hooks 字段,但校验部分明确说明“校验器会拒绝 hooks 这类不被接受的清单字段,因此脚手架生成的清单中不包含它”。validate_plugin.py 中的 allowed_keys 白名单(idnameversiondescriptionskillsappsmcpServersinterfaceauthorhomepagerepositorylicensekeywords)不包含 hooks,任何额外字段都会触发 “not accepted by plugin validation” 错误。编写清单时以白名单为准,hooks 目录可以存在但不应在 plugin.json 中声明。

marketplace.json 规范

marketplace.json 的位置取决于插件应该放在哪里:新建插件默认落到个人市场,除非调用方显式要求仓库本地位置:

  • 个人插件:~/.agents/plugins/marketplace.json
  • 仓库/团队插件:<repo-root>/.agents/plugins/marketplace.json

规范文档给出的完整示例:

{
  "name": "openai-curated",
  "interface": {
    "displayName": "ChatGPT Official"
  },
  "plugins": [
    {
      "name": "linear",
      "source": {
        "source": "local",
        "path": "./plugins/linear"
      },
      "policy": {
        "installation": "AVAILABLE",
        "authentication": "ON_INSTALL"
      },
      "category": "Productivity"
    }
  ]
}

顶层字段

字段 类型 说明
name string 市场标识符/目录名
interface object,可选 市场的展示元数据
plugins array 有序的插件条目列表,该顺序决定 Codex 的渲染顺序

interface.displayName(可选)是市场级的展示标题,必须放在顶层 interface 对象下,不能放进单个 plugins[] 条目中。

插件条目字段

字段 说明
name 插件标识符,须与插件目录名及 plugin.jsonname 一致
source.source 本地仓库工作流固定使用 local
source.path 相对市场根目录的插件路径,个人与仓库/团队市场统一使用 ./plugins/<plugin-name> 约定
policy.installation 可用性策略,允许值:NOT_AVAILABLEAVAILABLEINSTALLED_BY_DEFAULT;新条目默认 AVAILABLE
policy.authentication 认证时机策略,允许值:ON_INSTALLON_USE;新条目默认 ON_INSTALL
policy.products 可选的产品门控覆盖项,除非显式要求,否则省略
category 展示分类,必须包含

关于 source.path 的一个文档细节:以 ~/.agents/plugins/marketplace.json 为例,条目 ./plugins/<plugin-name> 解析到 ~/.agents/plugins/plugins/<plugin-name> 这类相对市场根的位置(原文示例写作 ~/plugins/<plugin-name>),关键点是路径解析始终以市场文件所在目录为根,两种市场位置共用同一套相对路径约定。

市场生成规则

规范文档列出的生成规则,与脚手架代码 create_basic_plugin.py 的行为一一对应:

  • 从零创建市场文件时,先写入顶层 nameinterface.displayName 再添加第一个插件条目;脚手架的 build_default_marketplace 默认以 personal 为市场名;
  • 每个生成或更新的插件条目都必须写全 policy.installationpolicy.authenticationcategory,即使取值就是默认值;
  • 新条目追加plugins[] 末尾,除非用户显式要求重排;仅当确需覆盖时,同名条目才会被替换(脚本中对应 --force,未加 --force 时同名条目会抛 FileExistsError);
  • 默认创建到个人市场;仓库/团队市场仅在用户明确要求时使用;
  • 只有当默认的 personal 市场名已被占用、且需要播种另一个新市场文件时才覆盖市场 name。从源码可见,--marketplace-name 不能用于就地重命名已存在的市场——若文件已存在,其顶层 name 必须与传入值一致,否则脚本直接报错。

校验规则与本地迭代流程

validate_plugin.py 的完整校验面

规范文档的 “Plugin validation notes” 一节给出了校验要点,完整清单如下(并附 validate_plugin.py 中的实现佐证):

  • 校验器镜像工作区插件摄入(ingestion)的 schema,使生成物从第一天起就符合同一份清单契约;
  • nameversiondescriptionauthor.name 及必填的 interface 字段必须为真实值;
  • version 使用严格 semver 正则(完整实现见脚本中的 SEMVER_RE,含预发布与构建元数据分支);
  • websiteURLprivacyPolicyURLtermsOfServiceURL 存在时必须是绝对 https:// URL;
  • composerIconlogologoDarkscreenshots 存在时必须指向插件目录内的真实文件;
  • apps 字段只有在 .app.json 真实存在时才应出现在 plugin.json 中;
  • mcpServers 可以指向 .mcp.json,也可以直接内联 MCP server 对象;
  • 校验拒绝 hooks 等不被支持的清单字段,因此脚手架不把它们写进生成物;
  • 额外的一条预检:递归拒绝任何 [TODO: ...] 占位符(reject_todo_markers 遍历整个 JSON 树)。

插件目录中若存在 skills/ 子目录,校验器还会逐个检查每个技能:SKILL.md 必须以 YAML frontmatter 开头、frontmatter 需为闭合的合法 YAML、namedescription 必填、disable-model-invocation 若出现必须为 false;技能下的 agents/openai.yaml(如 plugin-creator 自带的示例)只接受 interface/policy/dependencies 三个顶层键,其中 interface.display_nameinterface.short_description 必填,brand_color 同样要求 #RRGGBB

在交付任何生成物之前运行:

python3 scripts/validate_plugin.py <plugin-path>

更新已有本地插件:cachebuster 重装循环

当插件已存在且 marketplace 条目已指向正在编辑的源码时,installing-and-updating.md 定义了本地迭代的重装流程,核心是 update_plugin_cachebuster.py

  1. 改写清单版本号为单个 Codex cachebuster 后缀:
python3 scripts/update_plugin_cachebuster.py <plugin-path>

省略 --cachebuster 时,脚本用秒级精度的 UTC 时间戳作为 token(default_cachebuster 实现);仅当用户明确要求或外部工作流依赖特定 token 时才手动覆盖,例如 --cachebuster local-20260519-184516

  1. 读取个人市场名(默认读 ~/.agents/plugins/marketplace.json):
python3 scripts/read_marketplace_name.py
# 或其他市场文件
python3 scripts/read_marketplace_name.py --marketplace-path <path-to-marketplace.json>
  1. 从该市场重装插件:
codex plugin add <plugin-name>@<marketplace-name-from-marketplace-json>
  1. 若插件不在个人市场文件中,用 codex plugin list 确认是哪个本地市场在提供该插件,再从对应市场重装;非本地市场则先停下来排查不匹配问题。

  2. 重装完成后提示用户新开一个线程再试用,这是让 Codex 拾取新技能与工具的安全边界。

cachebuster 的改写策略在脚本中实现为:保留 + 之前的全部版本前缀,仅替换后缀为 +codex.<cachebuster>,token 本身会被清洗为小写字母、数字与连字符。参考文档给出的转换示例:

0.1.0                     -> 0.1.0+codex.local-20260519-184516
0.1.0+codex.old-token     -> 0.1.0+codex.local-20260519-184516
1.2.3-beta.1+codex.prev   -> 1.2.3-beta.1+codex.local-20260519-184516
dev-build+other-tag       -> dev-build+codex.local-20260519-184516

该文档同时强调:替换已有的 Codex cachebuster 而不是叠加新的;不要靠递增数字版本号来触发重装。市场操作应通过命令完成,而不是在更新/重装流程中手改 marketplace.jsonconfig.toml

快速参考:最小合法清单

结合规范与脚手架默认值,一个能通过 validate_plugin.py 的最小清单形态为(对照 build_plugin_json 的生成逻辑):

{
  "name": "my-plugin",
  "version": "0.1.0",
  "description": "My Plugin plugin",
  "author": {
    "name": "Local developer"
  },
  "skills": "./skills/",
  "interface": {
    "displayName": "My Plugin",
    "shortDescription": "Use My Plugin in Codex.",
    "longDescription": "My Plugin adds a local Codex plugin scaffold.",
    "developerName": "Local developer",
    "category": "Productivity",
    "capabilities": [],
    "defaultPrompt": "Help me use My Plugin."
  }
}

需要注意的落地约束总结:清单位置固定为 .codex-plugin/plugin.json;插件名与目录名一致且经过 kebab-case 规范化;skills/字符串 mcpServers 是“补充声明”而非“替代默认发现”;apps/mcpServers 字段必须与伴生文件共存亡;市场条目必须带全策略字段并以 ./plugins/<plugin-name> 作为统一相对路径。这些规则共同保证了生成物在个人市场(~/.agents/plugins/marketplace.json)与仓库/团队市场(<repo-root>/.agents/plugins/marketplace.json)两条路径下都遵循同一份摄入契约。

更完整的 Rust 侧插件管理实现(市场安装、策略解析、插件装载等)可以参考 core-plugins 模块,但就日常编写与调试清单而言,上述规范文档、四个 Python 脚本(create_basic_plugin.pyvalidate_plugin.pyupdate_plugin_cachebuster.pyread_marketplace_name.py)已经覆盖了从脚手架、校验到本地重装的全部工作流。

登录后查看全文
热门项目推荐
相关项目推荐