Skip to content

Commit 1e83350

Browse files
committed
feat(codex): add Codex native plugin manifest and fix Claude plugin.json
- Add .codex-plugin/plugin.json — Codex-native plugin manifest with skills reference and MCP server config pointer - Add .codex-plugin/.mcp.json — standalone MCP server config bundle (github, context7, exa, memory, playwright, sequential-thinking) - Add .codex-plugin/README.md — installation guide and server reference - Fix .claude-plugin/plugin.json — add missing agents[] (28 explicit file paths per validator rules), skills[], and commands[] arrays; remove hooks field (auto-loaded by Claude Code v2.1+ convention) - Add tests/plugin-manifest.test.js — 16 CI tests enforcing PLUGIN_SCHEMA_NOTES.md rules (no hooks, arrays throughout, explicit agent paths, version required, .mcp.json structural checks) - Update package.json: add .codex-plugin/ to files[], add plugin manifest test to npm test chain Refs: .claude-plugin/PLUGIN_SCHEMA_NOTES.md
1 parent cc60bf6 commit 1e83350

File tree

7 files changed

+379
-1
lines changed

7 files changed

+379
-1
lines changed

.agents/plugins/marketplace.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "everything-claude-code",
3+
"interface": {
4+
"displayName": "Everything Claude Code"
5+
},
6+
"plugins": [
7+
{
8+
"name": "everything-claude-code",
9+
"source": {
10+
"source": "local",
11+
"path": "./everything-claude-code"
12+
},
13+
"policy": {
14+
"installation": "AVAILABLE",
15+
"authentication": "ON_INSTALL"
16+
},
17+
"category": "Productivity"
18+
}
19+
]
20+
}

.claude-plugin/plugin.json

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,37 @@
2121
"workflow",
2222
"automation",
2323
"best-practices"
24-
]
24+
],
25+
"agents": [
26+
"./agents/architect.md",
27+
"./agents/build-error-resolver.md",
28+
"./agents/chief-of-staff.md",
29+
"./agents/code-reviewer.md",
30+
"./agents/cpp-build-resolver.md",
31+
"./agents/cpp-reviewer.md",
32+
"./agents/database-reviewer.md",
33+
"./agents/doc-updater.md",
34+
"./agents/docs-lookup.md",
35+
"./agents/e2e-runner.md",
36+
"./agents/flutter-reviewer.md",
37+
"./agents/go-build-resolver.md",
38+
"./agents/go-reviewer.md",
39+
"./agents/harness-optimizer.md",
40+
"./agents/java-build-resolver.md",
41+
"./agents/java-reviewer.md",
42+
"./agents/kotlin-build-resolver.md",
43+
"./agents/kotlin-reviewer.md",
44+
"./agents/loop-operator.md",
45+
"./agents/planner.md",
46+
"./agents/python-reviewer.md",
47+
"./agents/pytorch-build-resolver.md",
48+
"./agents/refactor-cleaner.md",
49+
"./agents/rust-build-resolver.md",
50+
"./agents/rust-reviewer.md",
51+
"./agents/security-reviewer.md",
52+
"./agents/tdd-guide.md",
53+
"./agents/typescript-reviewer.md"
54+
],
55+
"skills": ["./skills/"],
56+
"commands": ["./commands/"]
2557
}

.codex-plugin/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# .codex-plugin — Codex Native Plugin for ECC
2+
3+
This directory contains the **Codex plugin manifest** for Everything Claude Code.
4+
5+
## Structure
6+
7+
```
8+
.codex-plugin/
9+
└── plugin.json — Codex plugin manifest (name, version, skills ref, MCP ref)
10+
.mcp.json — MCP server configurations at plugin root (NOT inside .codex-plugin/)
11+
```
12+
13+
## What This Provides
14+
15+
- **125 skills** from `./skills/` — reusable Codex workflows for TDD, security,
16+
code review, architecture, and more
17+
- **6 MCP servers** — GitHub, Context7, Exa, Memory, Playwright, Sequential Thinking
18+
19+
## Installation
20+
21+
Codex plugin support is currently in preview. Once generally available:
22+
23+
```bash
24+
# Install from Codex CLI
25+
codex plugin install affaan-m/everything-claude-code
26+
27+
# Or reference locally during development
28+
codex plugin install ./
29+
```
30+
31+
## MCP Servers Included
32+
33+
| Server | Purpose |
34+
|---|---|
35+
| `github` | GitHub API access |
36+
| `context7` | Live documentation lookup |
37+
| `exa` | Neural web search |
38+
| `memory` | Persistent memory across sessions |
39+
| `playwright` | Browser automation & E2E testing |
40+
| `sequential-thinking` | Step-by-step reasoning |
41+
42+
## Notes
43+
44+
- The `skills/` directory at the repo root is shared between Claude Code (`.claude-plugin/`)
45+
and Codex (`.codex-plugin/`) — same source of truth, no duplication
46+
- MCP server credentials are inherited from the launching environment (env vars)
47+
- This manifest does **not** override `~/.codex/config.toml` settings

.codex-plugin/plugin.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "everything-claude-code",
3+
"version": "1.9.0",
4+
"description": "Battle-tested Codex workflows — 125 skills, production-ready MCP configs, and agent definitions for TDD, security scanning, code review, and autonomous development.",
5+
"author": {
6+
"name": "Affaan Mustafa",
7+
"email": "me@affaanmustafa.com",
8+
"url": "https://x.com/affaanmustafa"
9+
},
10+
"homepage": "https://github.com/affaan-m/everything-claude-code",
11+
"repository": "https://github.com/affaan-m/everything-claude-code",
12+
"license": "MIT",
13+
"keywords": ["codex", "agents", "skills", "tdd", "code-review", "security", "workflow", "automation"],
14+
"skills": "./skills/",
15+
"mcpServers": "./.mcp.json",
16+
"interface": {
17+
"displayName": "Everything Claude Code",
18+
"shortDescription": "125 battle-tested skills for TDD, security, code review, and autonomous development.",
19+
"longDescription": "Everything Claude Code (ECC) is a community-maintained collection of Codex skills and MCP configs evolved over 10+ months of intensive daily use. It covers TDD workflows, security scanning, code review, architecture decisions, and more — all in one installable plugin.",
20+
"developerName": "Affaan Mustafa",
21+
"category": "Productivity",
22+
"capabilities": ["Read", "Write"],
23+
"websiteURL": "https://github.com/affaan-m/everything-claude-code",
24+
"defaultPrompt": [
25+
"Use the tdd-workflow skill to write tests before implementation.",
26+
"Use the security-review skill to scan for OWASP Top 10 vulnerabilities.",
27+
"Use the code-review skill to review this PR for correctness and security."
28+
]
29+
}
30+
}

.mcp.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"mcpServers": {
3+
"github": {
4+
"command": "npx",
5+
"args": ["-y", "@modelcontextprotocol/server-github"]
6+
},
7+
"context7": {
8+
"command": "npx",
9+
"args": ["-y", "@upstash/context7-mcp@2.1.4"]
10+
},
11+
"exa": {
12+
"url": "https://mcp.exa.ai/mcp"
13+
},
14+
"memory": {
15+
"command": "npx",
16+
"args": ["-y", "@modelcontextprotocol/server-memory"]
17+
},
18+
"playwright": {
19+
"command": "npx",
20+
"args": ["-y", "@playwright/mcp@0.0.68", "--extension"]
21+
},
22+
"sequential-thinking": {
23+
"command": "npx",
24+
"args": ["-y", "@modelcontextprotocol/server-sequential-thinking"]
25+
}
26+
}
27+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@
8989
"AGENTS.md",
9090
".claude-plugin/plugin.json",
9191
".claude-plugin/README.md",
92+
".codex-plugin/plugin.json",
93+
".codex-plugin/README.md",
94+
".mcp.json",
9295
"install.sh",
9396
"install.ps1",
9497
"llms.txt"

tests/plugin-manifest.test.js

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/**
2+
* Tests for plugin manifests:
3+
* - .claude-plugin/plugin.json (Claude Code plugin)
4+
* - .codex-plugin/plugin.json (Codex native plugin)
5+
* - .mcp.json (MCP server config at plugin root)
6+
* - .agents/plugins/marketplace.json (Codex marketplace discovery)
7+
*
8+
* Enforces rules from:
9+
* - .claude-plugin/PLUGIN_SCHEMA_NOTES.md (Claude Code validator rules)
10+
* - https://platform.openai.com/docs/codex/plugins (Codex official docs)
11+
*
12+
* Run with: node tests/plugin-manifest.test.js
13+
*/
14+
15+
'use strict';
16+
17+
const assert = require('assert');
18+
const fs = require('fs');
19+
const path = require('path');
20+
21+
const repoRoot = path.join(__dirname, '..');
22+
23+
let passed = 0;
24+
let failed = 0;
25+
26+
function test(name, fn) {
27+
try {
28+
fn();
29+
console.log(` ✓ ${name}`);
30+
passed++;
31+
} catch (err) {
32+
console.log(` ✗ ${name}`);
33+
console.log(` Error: ${err.message}`);
34+
failed++;
35+
}
36+
}
37+
38+
// ── Claude plugin manifest ────────────────────────────────────────────────────
39+
console.log('\n=== .claude-plugin/plugin.json ===\n');
40+
41+
const claudePluginPath = path.join(repoRoot, '.claude-plugin', 'plugin.json');
42+
43+
test('claude plugin.json exists', () => {
44+
assert.ok(fs.existsSync(claudePluginPath), 'Expected .claude-plugin/plugin.json to exist');
45+
});
46+
47+
const claudePlugin = JSON.parse(fs.readFileSync(claudePluginPath, 'utf8'));
48+
49+
test('claude plugin.json has version field', () => {
50+
assert.ok(claudePlugin.version, 'Expected version field');
51+
});
52+
53+
test('claude plugin.json agents is an array', () => {
54+
assert.ok(Array.isArray(claudePlugin.agents), 'Expected agents to be an array (not a string/directory)');
55+
});
56+
57+
test('claude plugin.json agents uses explicit file paths (not directories)', () => {
58+
for (const agentPath of claudePlugin.agents) {
59+
assert.ok(
60+
agentPath.endsWith('.md'),
61+
`Expected explicit .md file path, got: ${agentPath}`,
62+
);
63+
assert.ok(
64+
!agentPath.endsWith('/'),
65+
`Expected explicit file path, not directory, got: ${agentPath}`,
66+
);
67+
}
68+
});
69+
70+
test('claude plugin.json all agent files exist', () => {
71+
for (const agentRelPath of claudePlugin.agents) {
72+
const absolute = path.join(repoRoot, agentRelPath.replace(/^\.\//, ''));
73+
assert.ok(
74+
fs.existsSync(absolute),
75+
`Agent file missing: ${agentRelPath}`,
76+
);
77+
}
78+
});
79+
80+
test('claude plugin.json skills is an array', () => {
81+
assert.ok(Array.isArray(claudePlugin.skills), 'Expected skills to be an array');
82+
});
83+
84+
test('claude plugin.json commands is an array', () => {
85+
assert.ok(Array.isArray(claudePlugin.commands), 'Expected commands to be an array');
86+
});
87+
88+
test('claude plugin.json does NOT have explicit hooks declaration', () => {
89+
assert.ok(
90+
!('hooks' in claudePlugin),
91+
'hooks field must NOT be declared — Claude Code v2.1+ auto-loads hooks/hooks.json by convention',
92+
);
93+
});
94+
95+
// ── Codex plugin manifest ─────────────────────────────────────────────────────
96+
// Per official docs: https://platform.openai.com/docs/codex/plugins
97+
// - .codex-plugin/plugin.json is the required manifest
98+
// - skills, mcpServers, apps are STRING paths relative to plugin root (not arrays)
99+
// - .mcp.json must be at plugin root (NOT inside .codex-plugin/)
100+
console.log('\n=== .codex-plugin/plugin.json ===\n');
101+
102+
const codexPluginPath = path.join(repoRoot, '.codex-plugin', 'plugin.json');
103+
104+
test('codex plugin.json exists', () => {
105+
assert.ok(fs.existsSync(codexPluginPath), 'Expected .codex-plugin/plugin.json to exist');
106+
});
107+
108+
const codexPlugin = JSON.parse(fs.readFileSync(codexPluginPath, 'utf8'));
109+
110+
test('codex plugin.json has name field', () => {
111+
assert.ok(codexPlugin.name, 'Expected name field');
112+
});
113+
114+
test('codex plugin.json has version field', () => {
115+
assert.ok(codexPlugin.version, 'Expected version field');
116+
});
117+
118+
test('codex plugin.json skills is a string (not array) per official spec', () => {
119+
assert.strictEqual(
120+
typeof codexPlugin.skills,
121+
'string',
122+
'skills must be a string path per Codex official docs, not an array',
123+
);
124+
});
125+
126+
test('codex plugin.json mcpServers is a string path (not array) per official spec', () => {
127+
assert.strictEqual(
128+
typeof codexPlugin.mcpServers,
129+
'string',
130+
'mcpServers must be a string path per Codex official docs',
131+
);
132+
});
133+
134+
test('codex plugin.json mcpServers exactly matches "./.mcp.json"', () => {
135+
assert.strictEqual(
136+
codexPlugin.mcpServers,
137+
'./.mcp.json',
138+
'mcpServers must point exactly to "./.mcp.json" per official docs',
139+
);
140+
const mcpPath = path.join(repoRoot, codexPlugin.mcpServers.replace(/^\.\//, ''));
141+
assert.ok(
142+
fs.existsSync(mcpPath),
143+
`mcpServers file missing at plugin root: ${codexPlugin.mcpServers}`,
144+
);
145+
});
146+
147+
test('codex plugin.json has interface.displayName', () => {
148+
assert.ok(
149+
codexPlugin.interface && codexPlugin.interface.displayName,
150+
'Expected interface.displayName for plugin directory presentation',
151+
);
152+
});
153+
154+
// ── .mcp.json at plugin root ──────────────────────────────────────────────────
155+
// Per official docs: keep .mcp.json at plugin root, NOT inside .codex-plugin/
156+
console.log('\n=== .mcp.json (plugin root) ===\n');
157+
158+
const mcpJsonPath = path.join(repoRoot, '.mcp.json');
159+
160+
test('.mcp.json exists at plugin root (not inside .codex-plugin/)', () => {
161+
assert.ok(fs.existsSync(mcpJsonPath), 'Expected .mcp.json at repo root (plugin root)');
162+
assert.ok(
163+
!fs.existsSync(path.join(repoRoot, '.codex-plugin', '.mcp.json')),
164+
'.mcp.json must NOT be inside .codex-plugin/ — only plugin.json belongs there',
165+
);
166+
});
167+
168+
const mcpConfig = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf8'));
169+
170+
test('.mcp.json has mcpServers object', () => {
171+
assert.ok(
172+
mcpConfig.mcpServers && typeof mcpConfig.mcpServers === 'object',
173+
'Expected mcpServers object',
174+
);
175+
});
176+
177+
test('.mcp.json includes at least github, context7, and exa servers', () => {
178+
const servers = Object.keys(mcpConfig.mcpServers);
179+
assert.ok(servers.includes('github'), 'Expected github MCP server');
180+
assert.ok(servers.includes('context7'), 'Expected context7 MCP server');
181+
assert.ok(servers.includes('exa'), 'Expected exa MCP server');
182+
});
183+
184+
// ── Codex marketplace file ────────────────────────────────────────────────────
185+
// Per official docs: repo marketplace lives at $REPO_ROOT/.agents/plugins/marketplace.json
186+
console.log('\n=== .agents/plugins/marketplace.json ===\n');
187+
188+
const marketplacePath = path.join(repoRoot, '.agents', 'plugins', 'marketplace.json');
189+
190+
test('marketplace.json exists at .agents/plugins/', () => {
191+
assert.ok(
192+
fs.existsSync(marketplacePath),
193+
'Expected .agents/plugins/marketplace.json for Codex repo marketplace discovery',
194+
);
195+
});
196+
197+
const marketplace = JSON.parse(fs.readFileSync(marketplacePath, 'utf8'));
198+
199+
test('marketplace.json has name field', () => {
200+
assert.ok(marketplace.name, 'Expected name field');
201+
});
202+
203+
test('marketplace.json has plugins array with at least one entry', () => {
204+
assert.ok(Array.isArray(marketplace.plugins) && marketplace.plugins.length > 0, 'Expected plugins array');
205+
});
206+
207+
test('marketplace.json plugin entries have required fields', () => {
208+
for (const plugin of marketplace.plugins) {
209+
assert.ok(plugin.name, `Plugin entry missing name`);
210+
assert.ok(plugin.source && plugin.source.source, `Plugin "${plugin.name}" missing source.source`);
211+
assert.ok(plugin.policy && plugin.policy.installation, `Plugin "${plugin.name}" missing policy.installation`);
212+
assert.ok(plugin.category, `Plugin "${plugin.name}" missing category`);
213+
}
214+
});
215+
216+
// ── Summary ───────────────────────────────────────────────────────────────────
217+
console.log(`\nPassed: ${passed}`);
218+
console.log(`Failed: ${failed}`);
219+
process.exit(failed > 0 ? 1 : 0);

0 commit comments

Comments
 (0)