# Plugins & marketplaces in Codex

A Codex plugin is a folder with a plugin.json manifest, skills, an MCP config and hooks; a marketplace is a marketplace.json catalogue that you add with codex plugin marketplace add and install from with codex plugin add or /plugins.

Source: https://ai-sw-factory.mellicci.dev/fundamentals/plugins/codex

This page covers Codex CLI. The plugin documentation is shared between ChatGPT and Codex: the developer pages under `developers.openai.com/plugins` describe the same plugin and marketplace format that Codex installs, and this page uses them for the Codex parts only. The IDE extension doesn't support plugins.

## At a glance

| | Codex |
|---|---|
| Term | Plugin (manifest `plugin.json`) and marketplace (`marketplace.json`) |
| Configured in | Plugin: `plugin.json` at its root. Marketplace: `.agents/plugins/marketplace.json` in a repo or `~/.agents/plugins/`; sources registered in `[marketplaces.<name>]` of `config.toml` |
| Loads / runs | Installed into `~/.codex/plugins/cache/<marketplace>/<plugin>/<version>/`; skills and tools are available in a new session; hooks run only after you trust them |
| Scope & precedence | Installed per user; `enabled` is set in user or trusted-project `config.toml`, and project settings override user, cloud-managed and system defaults |

## Build the scenario

Plugin `ticket-service-kit` 1.0.0 lives in the marketplace repository `acme/agent-marketplace`:

```text
agent-marketplace/
├── .agents/plugins/marketplace.json
└── plugins/ticket-service-kit/
    ├── plugin.json
    ├── mcp.json
    ├── skills/add-migration/SKILL.md
    └── hooks/
        ├── hooks.json
        ├── format.sh
        ├── guard.sh
        └── log.sh
```

The `reviewer` subagent is not in this tree: the documentation doesn't list custom agents as a plugin component, so it stays in each project at `.codex/agents/reviewer.toml` (see [subagents](https://ai-sw-factory.mellicci.dev/fundamentals/subagents/codex)).

`plugins/ticket-service-kit/plugin.json`:

```json
{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
  "name": "ticket-service-kit",
  "version": "1.0.0",
  "description": "Migration skill, format/guard/log hooks and GitHub MCP for ticket-service"
}
```

Skills are discovered from the root `skills/` directory and hooks from `hooks/hooks.json`, so the manifest lists neither. `hooks/hooks.json` uses the regular hooks schema, with `${PLUGIN_ROOT}` for the installed location (scripts as on the [hooks page](https://ai-sw-factory.mellicci.dev/fundamentals/hooks/codex)):

```json
{ "hooks": {
  "PreToolUse": [
    { "matcher": "Bash|apply_patch", "hooks": [{ "type": "command",
      "command": "${PLUGIN_ROOT}/hooks/guard.sh" }] },
    { "hooks": [{ "type": "command", "command": "${PLUGIN_ROOT}/hooks/log.sh" }] }],
  "PostToolUse": [
    { "matcher": "apply_patch", "hooks": [{ "type": "command",
      "command": "${PLUGIN_ROOT}/hooks/format.sh" }] }]
} }
```

`mcp.json` bundles the `github` server. The documentation doesn't show how a bundled server reads a token from `GITHUB_MCP_TOKEN`, so this file carries no credential; keep the `[mcp_servers.github]` table from the [MCP page](https://ai-sw-factory.mellicci.dev/fundamentals/mcp/codex) in the project instead if you need the token.

```json
{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
  "mcpServers": {
    "github": { "type": "streamable-http", "url": "https://api.githubcopilot.com/mcp/" }
  }
}
```

`.agents/plugins/marketplace.json`:

```json
{
  "name": "acme-agent-marketplace",
  "plugins": [
    {
      "name": "ticket-service-kit",
      "source": { "source": "local", "path": "./plugins/ticket-service-kit" },
      "policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" },
      "category": "Productivity"
    }
  ]
}
```

| Step | What you run | Where |
|---|---|---|
| Add the marketplace | `codex plugin marketplace add acme/agent-marketplace` (optional `--ref main`) | Shell |
| Install | `codex plugin add ticket-service-kit@acme-agent-marketplace`, or `/plugins` and pick it | Shell or TUI |
| Start fresh, trust hooks | New session, then review the three hooks in `/hooks` | TUI |
| Update | `codex plugin marketplace upgrade acme-agent-marketplace` | Shell |
| Disable | `/plugins`, <kbd>Space</kbd> on the plugin; or `enabled = false` (below) | TUI or config |

## Specifics

### Plugin layout and manifest

| Item | Detail |
|---|---|
| Portable manifest | `plugin.json` at the plugin root with `$schema`, `name` (kebab-case, also the identifier and namespace), `version`, `description`; optional `author`, `homepage`, `repository`, `license`, `keywords` |
| Fixed paths | `skills/`, `mcp.json`, `assets/` at the root |
| OpenAI settings | `extensions.com.openai` in `plugin.json`: `apps`, `hooks`, `interface` (display name, icons, default prompts) |
| Older layout | `.codex-plugin/plugin.json`, still supported as a compatibility fallback and what `@plugin-creator` scaffolds; if `extensions.com.openai` exists it replaces that overlay entirely, no merge |
| Paths inside manifests | Relative to the plugin root, start with `./`, stay inside the root |

The documentation says Claude-compatible and legacy manifests are also accepted, but new packages should use the portable `plugin.json`.

### What a plugin can contain

| Component | In a Codex plugin? | In the scenario |
|---|---|---|
| Skills | Yes, `skills/<name>/SKILL.md` | `add-migration` |
| MCP servers | Yes, `mcp.json` (older layout: `.mcp.json`, plus `.app.json` for registered apps) | `github` |
| Hooks | Yes, `hooks/hooks.json` by default, or `hooks` in the manifest (path, array of paths, or inline object); an explicit value replaces the default file | `format.sh`, `guard.sh`, `log.sh` |
| Browser extensions | Mentioned as a part; the documentation gives no layout | Not used |
| Custom agents (subagents) | Not documented as a component | `reviewer` stays in `.codex/agents/` |

Hook commands receive `PLUGIN_ROOT` and `PLUGIN_DATA` (a writable directory); `CLAUDE_PLUGIN_ROOT` and `CLAUDE_PLUGIN_DATA` are also set for existing plugin hooks. Hooks are not supported in cloud-orchestrated ChatGPT Work, and hook scripts must exist in the execution environment.

### Marketplaces

| Item | Detail |
|---|---|
| Catalogue files | `$REPO_ROOT/.agents/plugins/marketplace.json` (repo), `~/.agents/plugins/marketplace.json` (personal), legacy-compatible `$REPO_ROOT/.claude-plugin/marketplace.json` |
| Top level | `name` (marketplace id), optional `interface.displayName`, `plugins[]` |
| Entry | `name`, `source`, and always `policy.installation` (`AVAILABLE`, `INSTALLED_BY_DEFAULT`, `NOT_AVAILABLE`), `policy.authentication` (on install or first use), `category` |
| `source` kinds | `local` with `path` (relative to the marketplace root, `./`-prefixed, inside it), `url`, `git-subdir` (`url`, `path`, `ref` or `sha`), `npm` (`package`, optional `version`, `registry`) |
| Sources you add | GitHub `owner/repo[@ref]`, HTTP(S) or SSH Git URL, local root directory; `--ref` pins, `--sparse PATH` for Git sources |
| Registered in config | `[marketplaces.<name>]`: `source_type` (`git` or `local`), `source`, `ref`, `sparse_paths` |

An entry whose source Codex can't resolve is skipped; the rest of the marketplace still loads.

### Install, update and scope

| Task | Command or UI |
|---|---|
| Browse, install, uninstall | `/plugins` in the CLI, tabs per marketplace |
| Install, list, remove | `codex plugin add <name>@<marketplace>`, `codex plugin list`, `codex plugin remove` (all accept `--json`) |
| Marketplaces | `codex plugin marketplace add`, `list`, `upgrade [name]`, `remove <name>` |
| Disable for a project | `[plugins."ticket-service-kit@acme-agent-marketplace"]` with `enabled = false` in `.codex/config.toml` (trusted projects) |
| Bundled MCP policy | `plugins.<plugin>.mcp_servers.<server>`: `enabled`, `default_tools_approval_mode`, `enabled_tools`, `disabled_tools`, per-tool `approval_mode` |

A marketplace refresh can install or refresh files for configured plugins even when `enabled = false`. The documentation doesn't say whether an installed plugin updates on its own, or how to pin an installed version beyond pinning the marketplace with `--ref` or an entry's `ref`, `sha` or npm `version`. It also uses both `name` and `name@marketplace` as the config key; the second is the one documented for `enabled`.

### Trust and management

| Topic | Detail |
|---|---|
| Hooks | Bundled hooks are non-managed: Codex skips them until you review and trust the current definition in `/hooks` |
| MCP servers | Normal sandbox and approval policy applies; services use their own authentication |
| Uninstall | Removes the bundle; separately connected MCP integrations stay connected |
| Admin controls | `requirements.toml`: `marketplaces.restrict_to_allowed_sources` with `allowed_sources`, a per-plugin MCP server allowlist, `allow_managed_hooks_only = true` (skips plugin hooks), `features.plugins` |
| Sign-in | With an API key you can use only supported OpenAI-curated plugins |

## Gotchas

- **Start a new session after installing.** Bundled skills and tools appear only in new sessions.
- **Trust the hooks.** Installing or enabling the plugin runs none of its hooks until you review them in `/hooks`; `allow_managed_hooks_only` skips them entirely.
- **The subagent isn't in the plugin.** Ship `reviewer.toml` through the project's `.codex/agents/`, for example from a repository template.
- **`source.path` is relative to the marketplace root,** not to `.agents/plugins/`, and must start with `./`.
- **Much of the plugin documentation is written for ChatGPT.** Its steps for creating and sharing plugins (Plugin Creator, workspace publishing) are web features; only the CLI commands and files above are what this page relies on.
