Write `plugins/ /.codex-plugin/plugin.json`, next to `.claude-plugin/`. The Codex marketplace installs the SOURCE plugin directory directly (`source.path: ./plugins/ `), so no transformed skill tree is committed — Codex reads `SKILL.md` natively from `plugins/<
(self, plugin: PluginSource, result: EmitResult)
| 569 | # ── Marketplace manifests (native install; reads source skills) ────────── |
| 570 | |
| 571 | def _emit_codex_plugin_manifest(self, plugin: PluginSource, result: EmitResult) -> None: |
| 572 | """Write `plugins/<plugin>/.codex-plugin/plugin.json`, next to `.claude-plugin/`. |
| 573 | |
| 574 | The Codex marketplace installs the SOURCE plugin directory directly |
| 575 | (`source.path: ./plugins/<plugin>`), so no transformed skill tree is committed — |
| 576 | Codex reads `SKILL.md` natively from `plugins/<plugin>/skills/` (`skills: "./skills/"`), |
| 577 | exactly as the Cursor marketplace does. This keeps the repo lean: only the tiny |
| 578 | manifest is committed, not a duplicated skill tree. Skills above Codex's 8 KB |
| 579 | injection cap are truncated by Codex at load; the transformed, cap-split copies |
| 580 | under `.codex/skills/` (gitignored) remain for the `~/.codex/skills` symlink recipe. |
| 581 | """ |
| 582 | manifest_path = Path("plugins") / plugin.name / ".codex-plugin" / "plugin.json" |
| 583 | result.written.append( |
| 584 | self.write( |
| 585 | manifest_path, |
| 586 | json.dumps(self._codex_plugin_manifest(plugin), indent=2) + "\n", |
| 587 | ) |
| 588 | ) |
| 589 | |
| 590 | def _codex_plugin_manifest(self, plugin: PluginSource) -> dict: |
| 591 | """Per-plugin `.codex-plugin/plugin.json` (mirrors the superpowers shape).""" |
no test coverage detected