All articles
platform engineering · advanced ·

Building a plugin marketplace: what we can learn from Codex's plugin system

How Codex's plugin architecture works under the hood — marketplace catalogs, plugin manifests, installation lifecycle, permission models, and the design decisions that make an agent plugin system installable and safe.

codexcoding-agentsmarketplacespatternsplugins

Every platform eventually needs a plugin system. VS Code has extensions. Chrome has extensions. npm has packages. AI coding agents are no different — they need a way to bundle and distribute reusable capabilities.

Codex’s plugin architecture is a worked example of how to build one. Plugins bundle skills, app integrations, and MCP servers into installable units distributed through marketplace catalogs. The architecture makes specific design choices worth understanding whether you’re building on Codex or designing your own agent plugin system.

What a plugin actually bundles

A plugin is a directory with a manifest. It can contain four kinds of components:

Plugin component types
ComponentDefined inPurpose
Skillsskills/<name>/SKILL.mdTask-specific instructions that load on demand
Apps.app.jsonConnections to external tools (GitHub, Slack, Gmail)
MCP Servers.mcp.jsonModel Context Protocol server configuration
Lifecycle hookshooks/hooks.jsonEvent-driven automation at session boundaries

Only the manifest at .codex-plugin/plugin.json is required. Everything else is optional. The minimal viable plugin packages one skill — that’s enough to be useful.

my-plugin/.codex-plugin/plugin.json json
{
  "name": "my-first-plugin",
  "version": "1.0.0",
  "description": "Reusable greeting workflow",
  "skills": "./skills/"
}

The plugin manifest

The manifest has three jobs: identify the plugin, point to bundled components, and provide install-surface metadata. Published plugins use a richer manifest:

.codex-plugin/plugin.json json
{
  "name": "my-plugin",
  "version": "0.1.0",
  "description": "Bundle reusable skills and app integrations.",
  "author": {
    "name": "Your team",
    "email": "team@example.com",
    "url": "https://example.com"
  },
  "homepage": "https://example.com/plugins/my-plugin",
  "repository": "https://github.com/example/my-plugin",
  "license": "MIT",
  "keywords": ["research", "crm"],
  "skills": "./skills/",
  "mcpServers": "./.mcp.json",
  "apps": "./.app.json",
  "hooks": "./hooks/hooks.json",
  "interface": {
    "displayName": "My Plugin",
    "shortDescription": "Reusable skills and apps",
    "longDescription": "Distribute skills and app integrations together.",
    "developerName": "Your team",
    "category": "Productivity",
    "capabilities": ["Read", "Write"],
    "websiteURL": "https://example.com",
    "privacyPolicyURL": "https://example.com/privacy",
    "termsOfServiceURL": "https://example.com/terms",
    "defaultPrompt": [
      "Use My Plugin to summarize new CRM notes.",
      "Use My Plugin to triage new customer follow-ups."
    ],
    "brandColor": "#10A37F",
    "composerIcon": "./assets/icon.png",
    "logo": "./assets/logo.png",
    "screenshots": ["./assets/screenshot-1.png"]
  }
}

The interface object is where install-surface design happens. displayName, shortDescription, and longDescription control how the plugin appears in directories. defaultPrompt provides starter prompts that appear in the composer. brandColor, composerIcon, and logo control visual presentation. privacyPolicyURL and termsOfServiceURL provide legal links.

The marketplace catalog

A marketplace is a JSON catalog of plugins. It’s what turns a directory of plugin files into something installable:

.agents/plugins/marketplace.json json
{
  "name": "local-example-plugins",
  "interface": {
    "displayName": "Local Example Plugins"
  },
  "plugins": [
    {
      "name": "my-plugin",
      "source": {
        "source": "local",
        "path": "./plugins/my-plugin"
      },
      "policy": {
        "installation": "AVAILABLE",
        "authentication": "ON_INSTALL"
      },
      "category": "Productivity"
    },
    {
      "name": "research-helper",
      "source": {
        "source": "local",
        "path": "./plugins/research-helper"
      },
      "policy": {
        "installation": "AVAILABLE",
        "authentication": "ON_INSTALL"
      },
      "category": "Productivity"
    }
  ]
}

Each marketplace entry specifies:

  • source — Where the plugin lives (local path or url/git-subdir for Git-backed plugins)
  • policy.installationAVAILABLE, INSTALLED_BY_DEFAULT, or NOT_AVAILABLE
  • policy.authentication — Whether auth happens ON_INSTALL or on first use
  • category — Grouping label in the plugin directory

Marketplace sources

Codex supports three source types:

Plugin source types
Source typeUse caseExample
localPlugin in a local directory{ "source": "local", "path": "./plugins/my-plugin" }
urlPlugin at a Git repository root{ "source": "url", "url": "https://github.com/example/plugin.git" }
git-subdirPlugin in a subdirectory of a Git repoAdd "path": "./plugins/remote-helper" and optional "ref"

Git-backed entries can pin to a ref (branch or tag) or sha. If Codex can’t resolve a marketplace entry’s source, it skips that plugin entry instead of failing the whole marketplace.

Marketplace files live at:

  • $REPO_ROOT/.agents/plugins/marketplace.json — repo-scoped catalog
  • ~/.agents/plugins/marketplace.json — personal catalog

The CLI can manage marketplace sources:

codex plugin marketplace add owner/repo
codex plugin marketplace add owner/repo --ref main
codex plugin marketplace add ./local-marketplace-root
codex plugin marketplace upgrade  # refresh all
codex plugin marketplace remove marketplace-name

Installation lifecycle

When a user installs a plugin, Codex copies it into a cache:

~/.codex/plugins/cache/$MARKETPLACE_NAME/$PLUGIN_NAME/$VERSION/

For local plugins, $VERSION is local. Codex loads the installed copy from this cache path, not directly from the marketplace entry. This means marketplace updates don’t affect installed plugins until the user re-installs.

After installation, the plugin is available immediately. Bundled skills appear in skill selectors. MCP servers are configured. Hooks are loaded. Apps may prompt for authentication on first use.

Permission and security model

Installing a plugin makes its workflows available, but existing approval settings still apply. The security model has layers:

  1. Installation policyINSTALLED_BY_DEFAULT vs. AVAILABLE controls who sees what.
  2. Approval settings — Your approval_policy still governs whether the agent needs permission before acting.
  3. App authentication — External services require their own auth. No data flows without consent.
  4. Sandbox policy — File access is still constrained by sandbox mode.

When Codex sends data through a bundled app, that app’s terms and privacy policy apply. Plugins don’t create new data-sharing paths — they wire existing services into the agent’s tool surface.

Building your own curated list

One marketplace can expose a single plugin while you’re testing, then grow into a larger catalog:

  1. Scaffold a plugin with $plugin-creator — it generates the manifest and can create a local marketplace entry.
  2. Add more plugins to the same marketplace file as you build them.
  3. The marketplace appears as a selectable source in the plugin directory.
  4. Restart Codex after changes. The plugin directory picks up marketplace file changes on restart.

What this means for platform builders

The plugin architecture makes several design choices worth noting:

  • JSON manifests, not code packages. Plugins are declarative — they point to components rather than executing initialization code. This makes them inspectable and safe to install.
  • Marketplaces are separate from plugins. A plugin doesn’t know about marketplaces. Marketplaces point to plugins. This decoupling means the same plugin can appear in multiple catalogs.
  • Cache-based installation. Codex copies plugins into a versioned cache rather than running them from source. This prevents marketplace changes from silently affecting installed plugins.
  • Progressive capability. The minimal plugin is one skill in a directory. You add apps, MCP servers, and hooks as needed. The architecture scales from personal workflow to team infrastructure.

Plugins bundle four component types

Skills, apps, MCP servers, and lifecycle hooks — all pointed to by a single JSON manifest. Only the manifest is required; everything else is optional.

Marketplaces are JSON catalogs, not stores

A marketplace file lists plugins with source locations, install policies, and display metadata. One marketplace can expose one plugin or a curated collection.

Cache-based installation prevents silent changes

Codex copies plugins into a versioned cache on install. Marketplace updates don't affect installed plugins — users must re-install to pick up changes.

Security is layered, not binary

Installation policy, approval settings, app authentication, and sandbox mode combine. No single switch makes a plugin safe or dangerous.

Skills author, plugins distribute

The development path: iterate locally as a skill, package as a plugin when stable. The architecture supports this progression naturally.