plugin-creator skill (openai/skills)
- Install
- SKILL.md (verbatim)
- Quick Start
- What this skill creates
- Marketplace workflow
- Required behavior
- Reference to exact spec sample
- Validation
- Other files in this skill
- references/plugin-json-spec.md (verbatim)
- Field guide
- Top-level fields
- interface fields
- Path conventions and defaults
- Marketplace field guide
- Top-level fields
- interface fields
- Plugin entry fields
- Marketplace generation rules
What it does. Create and scaffold plugin directories for Codex with a required .codex-plugin/plugin.json, optional plugin folders/files, and baseline placeholders you can edit before publishing or testing. Use when Codex needs to create a new local plugin, add optional plugin structure, or generate or update repo-root .agents/plugins/marketplace.json entries for plugin ordering and availability metadata. Part of openai/skills (Skills Catalog for Codex) (openai/skills).
| Upstream | openai/skills |
| Skill file | skills/.system/plugin-creator/SKILL.md |
| License | Apache-2.0 (skill folder LICENSE.txt) |
| Author | OpenAI |
| Fetched | 2026-09-10 |
Install
- Codex:
$skill-installerinstalls from this catalog (this one ships with Codex by default); other agents:npx skills add openai/skills --skill plugin-creator. - Raw file:
curl -sL https://raw.githubusercontent.com/openai/skills/HEAD/skills/.system/plugin-creator/SKILL.md
SKILL.md (verbatim)
name: plugin-creator
description: Create and scaffold plugin directories for Codex with a required `.codex-plugin/plugin.json`, optional plugin folders/files, and baseline placeholders you can edit before publishing or testing. Use when Codex needs to create a new local plugin, add optional plugin structure, or generate or update repo-root `.agents/plugins/marketplace.json` entries for plugin ordering and availability metadata.
Plugin Creator
Quick Start
- Run the scaffold script:
# Plugin names are normalized to lower-case hyphen-case and must be <= 64 chars.
# The generated folder and plugin.json name are always the same.
# Run from repo root (or replace .agents/... with the absolute path to this SKILL).
# By default creates in <repo_root>/plugins/<plugin-name>.
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py <plugin-name>
Open
<plugin-path>/.codex-plugin/plugin.jsonand replace[TODO: ...]placeholders.Generate or update the repo marketplace entry when the plugin should appear in Codex UI ordering:
# marketplace.json always lives at <repo-root>/.agents/plugins/marketplace.json
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin --with-marketplace
For a home-local plugin, treat <home> as the root and use:
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin \
--path ~/plugins \
--marketplace-path ~/.agents/plugins/marketplace.json \
--with-marketplace
- Generate/adjust optional companion folders as needed:
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin --path <parent-plugin-directory> \
--with-skills --with-hooks --with-scripts --with-assets --with-mcp --with-apps --with-marketplace
<parent-plugin-directory> is the directory where the plugin folder <plugin-name> will be created (for example ~/code/plugins).
What this skill creates
- If the user has not made the plugin location explicit, ask whether they want a repo-local plugin or a home-local plugin before generating marketplace entries.
- Creates plugin root at
/<parent-plugin-directory>/<plugin-name>/. - Always creates
/<parent-plugin-directory>/<plugin-name>/.codex-plugin/plugin.json. - Fills the manifest with the full schema shape, placeholder values, and the complete
interfacesection. - Creates or updates
<repo-root>/.agents/plugins/marketplace.jsonwhen--with-marketplaceis set.- If the marketplace file does not exist yet, seed top-level
nameplusinterface.displayNameplaceholders before adding the first plugin entry.
- If the marketplace file does not exist yet, seed top-level
<plugin-name>is normalized using skill-creator naming rules:My Plugin→my-pluginMy--Plugin→my-plugin- underscores, spaces, and punctuation are converted to
- - result is lower-case hyphen-delimited with consecutive hyphens collapsed
- Supports optional creation of:
skills/hooks/scripts/assets/.mcp.json.app.json
Marketplace workflow
marketplace.jsonalways lives at<repo-root>/.agents/plugins/marketplace.json.- For a home-local plugin, use the same convention with
<home>as the root:~/.agents/plugins/marketplace.jsonplus./plugins/<plugin-name>. - Marketplace root metadata supports top-level
nameplus optionalinterface.displayName. - Treat plugin order in
plugins[]as render order in Codex. Append new entries unless a user explicitly asks to reorder the list. displayNamebelongs inside the marketplaceinterfaceobject, not individualplugins[]entries.- Each generated marketplace entry must include all of:
policy.installationpolicy.authenticationcategory
- Default new entries to:
policy.installation: "AVAILABLE"policy.authentication: "ON_INSTALL"
- Override defaults only when the user explicitly specifies another allowed value.
- Allowed
policy.installationvalues:NOT_AVAILABLEAVAILABLEINSTALLED_BY_DEFAULT
- Allowed
policy.authenticationvalues:ON_INSTALLON_USE
- Treat
policy.productsas an override. Omit it unless the user explicitly requests product gating. - The generated plugin entry shape is:
{
"name": "plugin-name",
"source": {
"source": "local",
"path": "./plugins/plugin-name"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
}
Use
--forceonly when intentionally replacing an existing marketplace entry for the same plugin name.If
<repo-root>/.agents/plugins/marketplace.jsondoes not exist yet, create it with top-level"name", an"interface"object containing"displayName", and apluginsarray, then add the new entry.For a brand-new marketplace file, the root object should look like:
{
"name": "[TODO: marketplace-name]",
"interface": {
"displayName": "[TODO: Marketplace Display Name]"
},
"plugins": [
{
"name": "plugin-name",
"source": {
"source": "local",
"path": "./plugins/plugin-name"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
}
]
}
Required behavior
- Outer folder name and
plugin.json"name"are always the same normalized plugin name. - Do not remove required structure; keep
.codex-plugin/plugin.jsonpresent. - Keep manifest values as placeholders until a human or follow-up step explicitly fills them.
- If creating files inside an existing plugin path, use
--forceonly when overwrite is intentional. - Preserve any existing marketplace
interface.displayName. - When generating marketplace entries, always write
policy.installation,policy.authentication, andcategoryeven if their values are defaults. - Add
policy.productsonly when the user explicitly asks for that override. - Keep marketplace
source.pathrelative to repo root as./plugins/<plugin-name>.
Reference to exact spec sample
For the exact canonical sample JSON for both plugin manifests and marketplace entries, use:
references/plugin-json-spec.md
Validation
After editing SKILL.md, run:
python3 <path-to-skill-creator>/scripts/quick_validate.py .agents/skills/plugin-creator
Other files in this skill
references/plugin-json-spec.md (verbatim)
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:
- Repo plugin:
<repo-root>/.agents/plugins/marketplace.json - Local plugin:
~/.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.- Repo plugin:
./plugins/<plugin-name> - Local plugin in
~/.agents/plugins/marketplace.json:./plugins/<plugin-name>
- Repo plugin:
- The same relative path convention is used for both repo-rooted and home-rooted 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.
- Choose marketplace location to match the plugin destination:
- Repo plugin:
<repo-root>/.agents/plugins/marketplace.json - Local plugin:
~/.agents/plugins/marketplace.json
- Repo plugin:
Back to openai/skills (Skills Catalog for Codex) or Agent skills.