Plugins
A plugin is a distribution and composition unit for a cohesive, stable capability. It is not the place to begin authoring a workflow and not a generic folder for every agent-related file in an organization.
When to create a plugin
Start with a repo-local skill or configuration while one team is still learning the workflow. Create a plugin when at least one of these is true:
- multiple repositories or teams need to install and update the capability;
- multiple related skills need one namespace and release lifecycle;
- a workflow must ship with MCP configuration, connectors/apps, lifecycle hooks, or presentation assets;
- consumers need a marketplace, workspace installation, or controlled version rather than copied files.
Keep local configuration when the workflow is experimental, repo-specific, or personal. Packaging too early turns every routing adjustment into a release and hides whether the workflow itself is useful.
OpenAI plugin layout
my-plugin/├── .codex-plugin/│ └── plugin.json├── skills/│ └── my-skill/SKILL.md├── hooks/│ └── hooks.json├── .mcp.json├── .app.json└── assets/Only plugin.json belongs inside .codex-plugin/. The other components stay at
the plugin root. A minimal manifest is:
{ "name": "my-plugin", "version": "1.0.0", "description": "One cohesive reusable capability", "skills": "./skills/"}Use a stable kebab-case name because it becomes the plugin identifier and
component namespace. Paths are relative to the plugin root and should begin with
./. Published plugins should also identify the author, repository, license,
interface copy, and appropriate visual or policy links.
OpenAI plugins can package:
- one or more skills;
- lifecycle hooks;
- MCP server configuration through
.mcp.json; - ChatGPT app or connector mappings through
.app.json; - browser capabilities and scheduled-task templates where the target surface supports them;
- install-surface metadata and assets.
An enabled plugin’s default hook path is hooks/hooks.json; a manifest hooks
entry can instead specify one or more paths or inline objects. Installing a
plugin does not automatically trust its command hooks—the current definitions
must still be reviewed.
Anthropic plugin layout
Anthropic uses .claude-plugin/plugin.json and likewise keeps components at the
plugin root. Its documented component set additionally includes custom agents,
language-server configuration, background monitors, executables added to the
agent shell path, and limited default settings.
my-plugin/├── .claude-plugin/plugin.json├── skills/├── agents/├── hooks/hooks.json├── monitors/monitors.json├── bin/├── .mcp.json├── .lsp.json└── settings.jsonThe manifest is optional when standard locations are sufficient, but a shared
EOS release should normally keep one for identity and ownership. At the time
reviewed, settings.json supports only agent and subagentStatusLine;
unknown keys are ignored, so validate effective behaviour rather than JSON shape
alone.
Do not force those components into an OpenAI manifest that does not document them. For a dual-client package, use two manifests over one cohesive root, share portable skills and scripts, and keep client-specific hooks, agent profiles, or integration metadata explicit.
MCP and connector packaging
OpenAI’s .mcp.json may contain a direct server map:
{ "docs": { "command": "docs-mcp", "args": ["--stdio"] }}or a map wrapped in mcp_servers. .app.json points to ChatGPT app/connector
mappings. Packaging configuration does not remove the need to review server
authentication, exposed tools, network destinations, data sensitivity, approval
behavior, and failure modes.
Distribution
Anthropic development plugins can be loaded with --plugin-dir, combined by
repeating the flag, and refreshed with /reload-plugins. A local copy takes
precedence over an installed plugin of the same name unless managed policy
forces the state. Marketplace installations are copied into a versioned local
cache; old versions remain for a documented seven-day grace period so active
sessions do not break, and installed symlinks must resolve inside the plugin
directory.
OpenAI supports repository and personal marketplace catalogues at:
$REPO_ROOT/.agents/plugins/marketplace.json;~/.agents/plugins/marketplace.json.
Repository marketplace entries often point to ./plugins/<name>. Git-backed
entries should use an intentional ref or commit; package-registry sources need
an equally explicit version policy. Workspace sharing is appropriate when
selected teammates install through the desktop app; a marketplace is appropriate
for repo/CLI distribution and curated lists.
Anthropic uses marketplace metadata under .claude-plugin/. Maintain one
release identity across catalogues, but validate installation separately for
each client.
Test and release
Before release:
- validate both manifest shape and every relative path;
- test each skill’s explicit invocation, routing, and output independently;
- test each hook event with fixtures and in the client;
- start MCP servers in a clean environment and verify auth and tool schemas;
- review all scripts, binaries, remote sources, and network behavior as executable supply-chain inputs;
- verify hook trust prompts and project trust behavior;
- install from the actual marketplace path in a clean workspace;
- verify upgrade, rollback, disable, and uninstall behavior;
- publish ownership, compatibility, changelog, and retirement policy.
Also verify the activation boundary: OpenAI CLI and IDE installations require a new task or chat before bundled capabilities are available, while Anthropic supports explicit plugin reload. If a plugin needs a connector, authentication and revocation are separate from package installation.
When migrating local definitions into a plugin, remove or disable the originals after validation so duplicate skills and hooks do not both load.
Sources: OpenAI Build plugins, OpenAI Build skills, and Anthropic plugins.