Cross-Tool Plugin Manifest Comparison
Addendum to Codex Manifest Shape Report | June 26, 2026
Sources: OpenAI Codex docs, Anthropic Claude Code docs, Cursor official plugins repo, OpenCode docs, HuggingFace Context Course
Platforms compared: Codex, Claude Code, Cursor, OpenCode, Pi
Platform Architecture Models
The AI coding tool ecosystem splits into two fundamental approaches:
| Model | Platforms | Characteristics |
|---|---|---|
| Manifest-first | Codex, Claude Code | Declarative JSON manifest + root-level component dirs. No code runs at install time. |
| Code-first | OpenCode | JS/TS modules export hook functions. Plugin IS the code. |
| IDE-extension | Cursor (VS Code fork) | Inherits VS Code extension model + new plugin specs |
| Package-based | Pi | package.json with convention-based directories |
Side-by-Side Manifest Comparison
Codex .codex-plugin/plugin.json
{
"name": "text-processor-plugin",
"version": "1.0.0",
"description": "Text analysis skills",
"skills": "./skills/",
"mcpServers": "./.mcp.json",
"apps": "./.app.json",
"hooks": "./hooks/hooks.json",
"interface": {
"displayName": "Text Processor",
"shortDescription": "Analyze text with AI",
"category": "Productivity",
"capabilities": ["Read", "Write"],
"defaultPrompt": ["Analyze this text for readability"],
"brandColor": "#10A37F",
"logo": "./assets/logo.png"
}
}
Claude Code .claude-plugin/plugin.json
{
"name": "text-processor-plugin",
"version": "1.0.0",
"description": "Text analysis skills",
"author": { "name": "Your Name" }
}
Notable: Claude Code's manifest is much leaner — components are discovered by convention (directory presence), not pointed to by explicit paths. No interface object.
OpenCode (No Manifest — Code is the plugin)
// .opencode/plugins/text-processor-plugin.ts
import type { Plugin } from "@opencode-ai/plugin"
export const TextProcessorPlugin: Plugin = async ({ project, client, $, directory }) => {
return {
"tool.execute.before": async (input) => {
if (input.tool === "read") {
await client.app.log({ body: { message: "Consider text analysis" } })
}
}
}
}
Pi package.json
{
"name": "text-processor-plugin",
"version": "1.0.0",
"keywords": ["pi-package"],
"pi": {
"skills": ["./skills"],
"extensions": ["./extensions"],
"prompts": ["./prompts"],
"themes": ["./themes"]
}
}
Directory Structure Comparison
Codex
my-plugin/
├── .codex-plugin/
│ └── plugin.json ← Manifest (ONLY file here)
├── skills/
│ └── analyze-text/
│ └── SKILL.md
├── .mcp.json ← MCP server config
├── .app.json ← App/connector config
├── hooks/
│ └── hooks.json
└── assets/
├── logo.png
└── screenshot-1.png
Claude Code
my-plugin/
├── .claude-plugin/
│ └── plugin.json ← Manifest (ONLY file here)
├── skills/
│ └── analyze-text/
│ └── SKILL.md
├── agents/ ← UNIQUE: agent definitions
│ └── reviewer.md
├── .mcp.json ← MCP server config
├── .lsp.json ← UNIQUE: LSP server config
├── hooks/
│ └── hooks.json
├── monitors/ ← UNIQUE: background monitors
│ └── monitors.json
├── themes/ ← UNIQUE: color themes
│ └── dracula.json
└── README.md
OpenCode
my-project/
├── .opencode/
│ ├── plugins/
│ │ └── text-processor.ts ← Plugin IS the code
│ └── package.json
├── opencode.json ← npm plugin references
└── README.md
Pi
my-package/
├── package.json ← Manifest (no hidden dir)
├── skills/
│ └── analyze-text/
│ └── SKILL.md
├── extensions/ ← Runtime TS/JS extensions
│ └── text-processor.ts
├── prompts/
└── themes/
Manifest Field Comparison
| Field | Codex | Claude Code | OpenCode | Pi |
|---|---|---|---|---|
| Location | .codex-plugin/plugin.json |
.claude-plugin/plugin.json |
N/A (code-first) | package.json |
| Required | Only name |
Only name |
N/A | name |
| Name format | kebab-case | kebab-case | module export | npm-style |
| Version | Optional (semver) | Optional (semver or git SHA) | N/A | Required (semver) |
| Component pointers | Explicit ("skills": "./skills/") |
Convention-based (dirs auto-detected) | N/A | Explicit ("pi": {"skills": [...]}) |
| Interface/UI metadata | Rich interface object (15 fields) |
None — marketplace metadata in marketplace.json | N/A | None |
| MCP config | .mcp.json (pointed by manifest) |
.mcp.json (auto-detected at root) |
Separate config | Optional .mcp.json |
| Path rules | Must start with ./, no .. |
Must start with ./, no .. |
N/A | Standard node resolution |
| Forward-compat | extra maps preserve unknowns |
Unrecognized fields fail validation | N/A | Standard JSON |
| Validation | SDK (Elixir) — lenient, preserves extra | Strict schema — rejects unknowns | N/A | npm validation |
Component Types Supported
| Component | Codex | Claude Code | OpenCode | Cursor | Pi |
|---|---|---|---|---|---|
| Skills (SKILL.md) | ✅ | ✅ | ❌ (hooks instead) | ❌ | ✅ |
| MCP Servers | ✅ | ✅ | ❌ (separate) | ✅ (consumer) | ✅ (via adapter) |
| App Connectors | ✅ (.app.json) | ❌ | ❌ | ❌ | ❌ |
| Lifecycle Hooks | ✅ | ✅ (30+ events) | ✅ (25+ events) | ❌ | ❌ |
| Agents/Subagents | ❌ | ✅ (agents/) | ❌ | ❌ | ❌ |
| LSP Servers | ❌ | ✅ (.lsp.json) | ❌ | ❌ (VS Code native) | ❌ |
| Monitors | ❌ | ✅ (experimental) | ❌ | ❌ | ❌ |
| Themes | ❌ | ✅ (experimental) | ❌ | ❌ (VS Code native) | ✅ |
| Custom Tools | ❌ (via MCP) | ❌ (via MCP) | ✅ (in code) | ❌ | ✅ (in extensions) |
Distribution Models
| Dimension | Codex | Claude Code | OpenCode | Cursor |
|---|---|---|---|---|
| Primary distribution | Git repos | Git repos | npm + local files | VS Code Marketplace (OpenVSX) |
| Marketplace format | marketplace.json (JSON catalog) |
marketplace.json (JSON catalog) |
opencode.json array |
.vsix packages |
| Scopes | Official, Repo, Personal | User, Project, Local, Managed | Project-local | Global |
| Install cache | ~/.codex/plugins/cache/ |
~/.claude/plugins/ |
node_modules |
~/.vscode/extensions/ |
| Offline support | ✅ (cache persists) | ✅ (cache persists) | ✅ (npm cache) | ✅ |
| Version pinning | ref/sha in marketplace entry |
git SHA or explicit version | npm semver | Extension version |
| CLI install | codex plugin install |
claude plugin install |
npm install | ext install |
| Marketplace CLI | codex plugin marketplace add |
(marketplace.json file) | N/A | N/A |
| Policy controls | AVAILABLE/PREINSTALLED/HIDDEN |
Scoped settings | N/A | N/A |
Hook/Event Systems
| Aspect | Codex | Claude Code | OpenCode |
|---|---|---|---|
| Event count | ~5-6 (SessionStart, Turn, ToolCall) | 30+ events | 25+ events |
| Hook types | command only |
command, http, mcp_tool, prompt, agent |
JS/TS handler functions |
| Trust model | Non-managed (explicit user trust required) | Non-managed (explicit trust) | Auto-loaded (code in project) |
| Env vars | PLUGIN_ROOT, PLUGIN_DATA |
CLAUDE_PLUGIN_ROOT, CLAUDE_PLUGIN_DATA, CLAUDE_PROJECT_DIR |
Context object in code |
| Event matchers | N/A | Regex patterns (e.g., "Write|Edit") |
Tool name matching |
| Blocking | No | Yes (PreToolUse can block) | Yes (before hooks can block) |
Key Architectural Differences
1. Explicit Pointers vs Convention Discovery
Codex requires explicit manifest pointers:
{ "skills": "./skills/", "mcpServers": "./.mcp.json" }
Claude Code auto-discovers by directory presence — if skills/ exists at plugin root, skills are loaded. The manifest only needs name. This makes Claude Code plugins simpler to create but harder to reason about (implicit behavior).
2. Interface Metadata: Codex-Only
Codex has a rich interface object for marketplace presentation (brand colors, logos, screenshots, starter prompts). Claude Code has no equivalent in the manifest — all presentation metadata lives in the marketplace entry, not the plugin itself.
Why it matters: Codex plugins are self-describing for marketplace purposes. Claude Code plugins depend on their marketplace entry for discoverability.
3. App Connectors: Codex-Exclusive
Only Codex has .app.json for third-party service authentication (OAuth, API keys). Claude Code, OpenCode, and Cursor don't bundle auth connectors in their plugin systems — they expect MCP servers to handle external service integration.
Why it matters: Codex treats "connecting to Slack/GitHub/Figma" as a first-class plugin concern. Others offload this entirely to MCP.
4. Subagents: Claude Code-Exclusive
Only Claude Code supports agents/ directories with agent definitions (model selection, tool restrictions, isolation). Codex has no agent bundling — its "subagent" concept operates outside the plugin system.
5. LSP + Monitors + Themes: Claude Code's Breadth
Claude Code has the richest component surface: LSP servers (real-time code intelligence), monitors (background stdout watchers), and themes. These make Claude Code plugins closer to full IDE extensions. Codex is narrower but cleaner.
6. Validation Philosophy
| Codex | Claude Code | |
|---|---|---|
| Unknown keys | Preserved in extra maps |
Rejected — validation fails |
| Forward compat | ✅ Survives round-trips | ❌ Must remove unknowns |
| Strictness | Lenient (only name required) | Strict (schema enforcement) |
This is a significant divergence: Codex plugins can carry forward-compatible experimental fields. Claude Code's strict validation means older tools break on newer manifest features.
7. Cross-Tool Portability
| Layer | Portable? | Notes |
|---|---|---|
| MCP servers | ✅ Universal | Same .mcp.json works across Codex, Claude Code, Cursor |
| Skills (SKILL.md) | 🟡 Near-portable | Same format, different auto-discovery/invocation |
| Hooks | ❌ Tool-specific | Different events, different schemas |
| Manifest | ❌ Tool-specific | .codex-plugin/ ≠ .claude-plugin/ |
| Marketplace | 🟡 Near-portable | Same JSON format, different paths |
MCP is the universal interop layer. A well-built MCP server works across all tools. Everything above MCP (skills, hooks, marketplace metadata) is tool-specific — but the functional logic (the MCP server code) is write-once, run-anywhere.
Summary: When to Use Which Model
| If you want... | Best platform model |
|---|---|
| Declarative, inspectable plugins | Codex or Claude Code (manifest-first) |
| Rich marketplace presentation | Codex (interface object) |
| Maximum component variety | Claude Code (agents, LSP, monitors, themes) |
| Cross-team distribution | Codex or Claude Code (Git marketplaces) |
| Code-level hook control | OpenCode (programmatic hooks) |
| IDE-native extensions | Cursor (VS Code model) |
| MCP portability | All (MCP is universal) |
| Forward-compatible schemas | Codex (extra maps) |
| Strict validation safety | Claude Code (rejects unknowns) |
| Third-party service auth | Codex (.app.json connectors) |
The Convergence Thesis
Despite surface differences, the ecosystem is converging:
- MCP as universal glue — All tools consume MCP servers. This is the write-once layer.
- Skills as a shared concept — SKILL.md with YAML frontmatter appears in Codex, Claude Code, and Pi. The format is nearly identical.
- Git-native distribution — Both Codex and Claude Code use
marketplace.jsoncatalogs pointing at Git repos. No compilation step, no build system. - Plugin = directory — Both manifest-first platforms share the same physical pattern: a hidden config dir (
.codex-plugin/or.claude-plugin/) withplugin.json, and all components at the plugin root.
The key difference is scope of ambition: Codex focuses on Skills + MCP + Apps (clean, portable). Claude Code maximizes component variety (agents, LSP, monitors, themes). OpenCode goes programmatic (full JS/TS control). But MCP underneath means the functional tools are portable regardless of which wrapper you choose.
Sources: OpenAI Codex Plugins, Claude Code Plugins Reference, Cursor Plugin Ecosystem, OpenCode Plugins, HuggingFace Context Course Unit 3