Codex 插件清单规范详解:plugin.json 与 marketplace.json 的字段、默认值与校验规则
本篇技术指南围绕 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.json。SKILL.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 Plugin→my-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 | 许可标识,如 MIT、Apache-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.json(validate_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 的实现,可以确认规范文档之外的若干硬性要求:
interface中displayName、shortDescription、longDescription、developerName、category五个字段全部必填且为非空字符串;defaultPrompt必填(同时接受defaultPrompt或default_prompt键名),且capabilities必须是字符串数组;brandColor用正则^#[0-9A-F]{6}$(忽略大小写)校验,不符合即报错;websiteURL、privacyPolicyURL、termsOfServiceURL若存在,必须是绝对https://URL(urlparse检查 scheme 与 netloc);composerIcon、logo、logoDark、screenshots每一项都会解析到磁盘,路径必须留在插件目录内部(拒绝绝对路径和..段)且文件必须真实存在。
路径约定与默认行为
规范文档对路径的约定如下,这些约定在脚手架与校验代码中均得到印证:
- 路径值应为相对路径且以
./开头; skills、hooks与字符串形态的mcpServers是在默认组件发现(default component discovery)之上补充声明,不会替换默认发现逻辑——从源码结构看,这是“显式声明 + 约定目录”双轨并行的设计;- 自定义路径值必须遵循插件根目录约定与命名/命名空间规则;
- 脚手架的清单固定写在
.codex-plugin/plugin.json。
一个值得特别注意的矛盾点:规范示例中虽然出现了 hooks 字段,但校验部分明确说明“校验器会拒绝 hooks 这类不被接受的清单字段,因此脚手架生成的清单中不包含它”。validate_plugin.py 中的 allowed_keys 白名单(id、name、version、description、skills、apps、mcpServers、interface、author、homepage、repository、license、keywords)不包含 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.json 的 name 一致 |
source.source |
本地仓库工作流固定使用 local |
source.path |
相对市场根目录的插件路径,个人与仓库/团队市场统一使用 ./plugins/<plugin-name> 约定 |
policy.installation |
可用性策略,允许值:NOT_AVAILABLE、AVAILABLE、INSTALLED_BY_DEFAULT;新条目默认 AVAILABLE |
policy.authentication |
认证时机策略,允许值:ON_INSTALL、ON_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 的行为一一对应:
- 从零创建市场文件时,先写入顶层
name与interface.displayName再添加第一个插件条目;脚手架的build_default_marketplace默认以personal为市场名; - 每个生成或更新的插件条目都必须写全
policy.installation、policy.authentication和category,即使取值就是默认值; - 新条目追加到
plugins[]末尾,除非用户显式要求重排;仅当确需覆盖时,同名条目才会被替换(脚本中对应--force,未加--force时同名条目会抛FileExistsError); - 默认创建到个人市场;仓库/团队市场仅在用户明确要求时使用;
- 只有当默认的
personal市场名已被占用、且需要播种另一个新市场文件时才覆盖市场name。从源码可见,--marketplace-name不能用于就地重命名已存在的市场——若文件已存在,其顶层name必须与传入值一致,否则脚本直接报错。
校验规则与本地迭代流程
validate_plugin.py 的完整校验面
规范文档的 “Plugin validation notes” 一节给出了校验要点,完整清单如下(并附 validate_plugin.py 中的实现佐证):
- 校验器镜像工作区插件摄入(ingestion)的 schema,使生成物从第一天起就符合同一份清单契约;
name、version、description、author.name及必填的interface字段必须为真实值;version使用严格 semver 正则(完整实现见脚本中的SEMVER_RE,含预发布与构建元数据分支);websiteURL、privacyPolicyURL、termsOfServiceURL存在时必须是绝对https://URL;composerIcon、logo、logoDark、screenshots存在时必须指向插件目录内的真实文件;apps字段只有在.app.json真实存在时才应出现在plugin.json中;mcpServers可以指向.mcp.json,也可以直接内联 MCP server 对象;- 校验拒绝
hooks等不被支持的清单字段,因此脚手架不把它们写进生成物; - 额外的一条预检:递归拒绝任何
[TODO: ...]占位符(reject_todo_markers遍历整个 JSON 树)。
插件目录中若存在 skills/ 子目录,校验器还会逐个检查每个技能:SKILL.md 必须以 YAML frontmatter 开头、frontmatter 需为闭合的合法 YAML、name 与 description 必填、disable-model-invocation 若出现必须为 false;技能下的 agents/openai.yaml(如 plugin-creator 自带的示例)只接受 interface/policy/dependencies 三个顶层键,其中 interface.display_name 与 interface.short_description 必填,brand_color 同样要求 #RRGGBB。
在交付任何生成物之前运行:
python3 scripts/validate_plugin.py <plugin-path>
更新已有本地插件:cachebuster 重装循环
当插件已存在且 marketplace 条目已指向正在编辑的源码时,installing-and-updating.md 定义了本地迭代的重装流程,核心是 update_plugin_cachebuster.py:
- 改写清单版本号为单个 Codex cachebuster 后缀:
python3 scripts/update_plugin_cachebuster.py <plugin-path>
省略 --cachebuster 时,脚本用秒级精度的 UTC 时间戳作为 token(default_cachebuster 实现);仅当用户明确要求或外部工作流依赖特定 token 时才手动覆盖,例如 --cachebuster local-20260519-184516。
- 读取个人市场名(默认读
~/.agents/plugins/marketplace.json):
python3 scripts/read_marketplace_name.py
# 或其他市场文件
python3 scripts/read_marketplace_name.py --marketplace-path <path-to-marketplace.json>
- 从该市场重装插件:
codex plugin add <plugin-name>@<marketplace-name-from-marketplace-json>
-
若插件不在个人市场文件中,用
codex plugin list确认是哪个本地市场在提供该插件,再从对应市场重装;非本地市场则先停下来排查不匹配问题。 -
重装完成后提示用户新开一个线程再试用,这是让 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.json 或 config.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.py、validate_plugin.py、update_plugin_cachebuster.py、read_marketplace_name.py)已经覆盖了从脚手架、校验到本地重装的全部工作流。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00