8.4 KiB
8.4 KiB
Plugin JSON sample spec
{
"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",
"screenshots": [
"./assets/screenshot1.png",
"./assets/screenshot2.png",
"./assets/screenshot3.png"
]
}
}
Field guide
Top-level fields
name(string): Plugin identifier (kebab-case, no spaces). Required ifplugin.jsonis provided and used as manifest name and component namespace.version(string): Plugin semantic version.description(string): Short purpose summary.author(object): Publisher identity.name(string): Author or team name.email(string): Contact email.url(string): Author/team homepage or profile URL.
homepage(string): Documentation URL for plugin usage.repository(string): Source code URL.license(string): License identifier (for exampleMIT,Apache-2.0).keywords(arrayofstring): Search/discovery tags.skills(string): Relative path to skill directories/files.hooks(string): Hook config path.mcpServers(string): MCP config path.apps(string): App manifest path for plugin integrations.interface(object): Interface/UX metadata block for plugin presentation.
interface fields
displayName(string): User-facing title shown for the plugin.shortDescription(string): Brief subtitle used in compact views.longDescription(string): Longer description used on details screens.developerName(string): Human-readable publisher name.category(string): Plugin category bucket.capabilities(arrayofstring): Capability list from implementation.websiteURL(string): Public website for the plugin.privacyPolicyURL(string): Privacy policy URL.termsOfServiceURL(string): Terms of service URL.defaultPrompt(arrayofstring): Starter prompts shown in composer/UX context.- Include at most 3 strings. Entries after the first 3 are ignored and will not be included.
- Each string is capped at 128 characters. Longer entries are truncated.
- Prefer short starter prompts around 50 characters so they scan well in the UI.
brandColor(string): Theme color for the plugin card.composerIcon(string): Path to icon asset.logo(string): Path to logo asset.screenshots(arrayofstring): List of screenshot asset paths.- Screenshot entries must be PNG filenames and stored under
./assets/. - Keep file paths relative to plugin root.
- Screenshot entries must be PNG filenames and stored under
Path conventions and defaults
- Path values should be relative and begin with
./. skills,hooks, andmcpServersare supplemented on top of default component discovery; they do not replace defaults.- Custom path values must follow the plugin root convention and naming/namespacing rules.
- This repo’s scaffold writes
.codex-plugin/plugin.json; treat that as the manifest location this skill generates.
Marketplace JSON sample spec
marketplace.json depends on where the plugin should live. New plugin creation defaults to the
personal marketplace unless the caller explicitly requests a repo-local destination:
- Personal plugin:
~/.agents/plugins/marketplace.json - Repo/team plugin:
<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"
}
]
}
Marketplace field guide
Top-level fields
name(string): Marketplace identifier or catalog name.interface(object, optional): Marketplace presentation metadata.plugins(array): Ordered plugin entries. This order determines how Codex renders plugins.
interface fields
displayName(string, optional): User-facing marketplace title.
Plugin entry fields
name(string): Plugin identifier. Match the plugin folder name andplugin.jsonname.source(object): Plugin source descriptor.source(string): Uselocalfor this repo workflow.path(string): Relative plugin path based on the marketplace root.- Personal plugin in
~/.agents/plugins/marketplace.json:./plugins/<plugin-name> - Repo/team plugin:
./plugins/<plugin-name>
- Personal plugin in
- The same relative path convention is used for both personal and repo/team marketplaces.
- Example: with
~/.agents/plugins/marketplace.json,./plugins/<plugin-name>resolves to~/plugins/<plugin-name>.
- Example: with
policy(object): Marketplace policy block. Always include it.installation(string): Availability policy.- Allowed values:
NOT_AVAILABLE,AVAILABLE,INSTALLED_BY_DEFAULT - Default for new entries:
AVAILABLE
- Allowed values:
authentication(string): Authentication timing policy.- Allowed values:
ON_INSTALL,ON_USE - Default for new entries:
ON_INSTALL
- Allowed values:
products(arrayofstring, optional): Product override for this plugin entry. Omit it unless product gating is explicitly requested.
category(string): Display category bucket. Always include it.
Marketplace generation rules
displayNamebelongs under the top-levelinterfaceobject, not individual plugin entries.- When creating a new marketplace file from scratch, seed
interface.displayNamealongside top-levelname. - Always include
policy.installation,policy.authentication, andcategoryon every generated or updated plugin entry. - Treat
policy.productsas an override and omit it unless explicitly requested. - Append new entries unless the user explicitly requests reordering.
- Replace an existing entry for the same plugin only when overwrite is intentional.
- Default new plugin creation to the personal marketplace.
- Use a repo/team marketplace only when the user specifically requests that destination.
- Only override the marketplace
namewhen the defaultpersonalname is already taken or installed and you need to seed a different new marketplace file. - Choose marketplace location to match the selected destination:
- Personal plugin:
~/.agents/plugins/marketplace.json - Repo/team plugin:
<repo-root>/.agents/plugins/marketplace.json
- Personal plugin:
Plugin validation notes
- The validator mirrors the workspace plugin ingestion schema so generated plugins follow the same manifest contract from the start.
- Plugin manifests must include real values for
name,version,description,author.name, and the requiredinterfacefields. versionmust use strict semver.websiteURL,privacyPolicyURL, andtermsOfServiceURLmust be absolutehttps://URLs when present.composerIcon,logo, andscreenshotsmust point to real files inside the plugin archive when present.appsandmcpServersshould appear inplugin.jsononly when.app.jsonand.mcp.jsonactually exist.- Validation rejects unsupported manifest fields such as
hooks, so the scaffold keeps them out of generated manifests. - Run
scripts/validate_plugin.py <plugin-path>before handing back a generated plugin. It adds one intentional preflight check that rejects leftover[TODO: ...]placeholders.