Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 36 additions & 9 deletions .agents/skills/plugin-creator/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: plugin-creator
description: Create and scaffold plugin directories for Codex with a required `.codex-plugin/plugin.json`, optional plugin folders/files, and baseline placeholders you can edit before publishing or testing. Use when Codex needs to create a new local plugin, add optional plugin structure, or generate or update repo-root `.agents/plugins/marketplace.json` entries for plugin ordering and availability metadata.
description: Create and scaffold plugin directories for Codex with a required `.codex-plugin/plugin.json`, optional plugin folders/files, and baseline placeholders you can edit before publishing or testing. Use when Codex needs to create a new personal plugin, add optional plugin structure, or generate or update personal or repo-root `.agents/plugins/marketplace.json` entries for plugin ordering and availability metadata.
---

# Plugin Creator
Expand All @@ -13,34 +13,51 @@ description: Create and scaffold plugin directories for Codex with a required `.
# Plugin names are normalized to lower-case hyphen-case and must be <= 64 chars.
# The generated folder and plugin.json name are always the same.
# Run from repo root (or replace .agents/... with the absolute path to this SKILL).
# By default creates in <repo_root>/plugins/<plugin-name>.
# By default creates in ~/plugins/<plugin-name>.
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py <plugin-name>
```

2. Open `<plugin-path>/.codex-plugin/plugin.json` and replace `[TODO: ...]` placeholders.

3. Generate or update the repo marketplace entry when the plugin should appear in Codex UI ordering:
3. Generate or update the personal marketplace entry when the plugin should appear in Codex UI ordering:

```bash
# marketplace.json always lives at <repo-root>/.agents/plugins/marketplace.json
# Personal marketplace entries default to ~/.agents/plugins/marketplace.json.
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin --with-marketplace
```

If the current Git repo already has `.agents/plugins/marketplace.json` and the user has not said
whether the plugin is personal or shared with their team, ask before generating a marketplace entry.
When they choose the repo marketplace, use:

```bash
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin \
--path ./plugins \
--marketplace-path ./.agents/plugins/marketplace.json \
--with-marketplace
```

4. Generate/adjust optional companion folders as needed:

```bash
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin --path <parent-plugin-directory> \
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin \
--path <parent-plugin-directory> \
--marketplace-path <marketplace-json-path> \
--with-skills --with-hooks --with-scripts --with-assets --with-mcp --with-apps --with-marketplace
```

`<parent-plugin-directory>` is the directory where the plugin folder `<plugin-name>` will be created (for example `~/code/plugins`).

## What this skill creates

- Default marketplace-backed scaffolds are personal: `~/plugins/<plugin-name>/` plus
`~/.agents/plugins/marketplace.json`.
- If the current Git repo already has `.agents/plugins/marketplace.json` and the user has not said
personal vs team, ask which marketplace to update before generating a marketplace entry.
- Creates plugin root at `/<parent-plugin-directory>/<plugin-name>/`.
- Always creates `/<parent-plugin-directory>/<plugin-name>/.codex-plugin/plugin.json`.
- Fills the manifest with the full schema shape, placeholder values, and the complete `interface` section.
- Creates or updates `<repo-root>/.agents/plugins/marketplace.json` when `--with-marketplace` is set.
- Creates or updates the selected marketplace when `--with-marketplace` is set.
- If the marketplace file does not exist yet, seed top-level `name` plus `interface.displayName` placeholders before adding the first plugin entry.
- `<plugin-name>` is normalized using skill-creator naming rules:
- `My Plugin` → `my-plugin`
Expand All @@ -57,7 +74,8 @@ python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin -

## Marketplace workflow

- `marketplace.json` always lives at `<repo-root>/.agents/plugins/marketplace.json`.
- Personal plugins use `~/.agents/plugins/marketplace.json`.
- Repo/team plugins use `<repo-root>/.agents/plugins/marketplace.json`.
- Marketplace root metadata supports top-level `name` plus optional `interface.displayName`.
- Treat plugin order in `plugins[]` as render order in Codex. Append new entries unless a user explicitly asks to reorder the list.
- `displayName` belongs inside the marketplace `interface` object, not individual `plugins[]` entries.
Expand Down Expand Up @@ -95,7 +113,7 @@ python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin -
```

- Use `--force` only when intentionally replacing an existing marketplace entry for the same plugin name.
- If `<repo-root>/.agents/plugins/marketplace.json` does not exist yet, create it with top-level `"name"`, an `"interface"` object containing `"displayName"`, and a `plugins` array, then add the new entry.
- If the selected marketplace file does not exist yet, create it with top-level `"name"`, an `"interface"` object containing `"displayName"`, and a `plugins` array, then add the new entry.

- For a brand-new marketplace file, the root object should look like:

Expand Down Expand Up @@ -131,7 +149,16 @@ python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin -
- Preserve any existing marketplace `interface.displayName`.
- When generating marketplace entries, always write `policy.installation`, `policy.authentication`, and `category` even if their values are defaults.
- Add `policy.products` only when the user explicitly asks for that override.
- Keep marketplace `source.path` relative to repo root as `./plugins/<plugin-name>`.
- Keep marketplace `source.path` relative to the selected marketplace root as `./plugins/<plugin-name>`.
- When the workflow created or updated a marketplace-backed plugin, end the final user-facing
response with these two Markdown links, in this order, and do not add any text after them:
- `[View <normalized plugin name>](codex://plugins/view-local?marketplacePath=<absolute marketplace.json path>&pluginName=<normalized plugin name>)`
- `[Share <normalized plugin name>](codex://plugins/share-local?marketplacePath=<absolute marketplace.json path>&pluginName=<normalized plugin name>)`
- Replace the link-label placeholder and both deeplink placeholders with the real normalized plugin
name plus the real absolute marketplace path from the scaffolded plugin. URL-encode query
parameter values when needed.
- Do not emit the `View <normalized plugin name>` or `Share <normalized plugin name>` links when no marketplace entry was
created or updated.

## Reference to exact spec sample

Expand Down
23 changes: 19 additions & 4 deletions .agents/skills/plugin-creator/references/plugin-json-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@

# Marketplace JSON sample spec

`marketplace.json` always lives at `<repo-root>/.agents/plugins/marketplace.json`.
`marketplace.json` depends on where the plugin should live:

- Personal plugin: `~/.agents/plugins/marketplace.json`
- Repo/team plugin: `<repo-root>/.agents/plugins/marketplace.json`

```json
{
Expand All @@ -112,8 +115,10 @@
"source": "local",
"path": "./plugins/linear"
},
"installPolicy": "AVAILABLE",
"authPolicy": "ON_INSTALL",
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
}
]
Expand All @@ -137,7 +142,11 @@
- `name` (`string`): Plugin identifier. Match the plugin folder name and `plugin.json` `name`.
- `source` (`object`): Plugin source descriptor.
- `source` (`string`): Use `local` for this repo workflow.
- `path` (`string`): Relative plugin path, always `./plugins/<plugin-name>`.
- `path` (`string`): Relative plugin path based on the marketplace root.
- Personal plugin in `~/.agents/plugins/marketplace.json`: `./plugins/<plugin-name>`
- Repo/team plugin: `./plugins/<plugin-name>`
- The same relative path convention is used for both personal and repo/team marketplaces.
- Example: with `~/.agents/plugins/marketplace.json`, `./plugins/<plugin-name>` resolves to `~/plugins/<plugin-name>`.
- `policy` (`object`): Marketplace policy block. Always include it.
- `installation` (`string`): Availability policy.
- Allowed values: `NOT_AVAILABLE`, `AVAILABLE`, `INSTALLED_BY_DEFAULT`
Expand All @@ -156,3 +165,9 @@
- Treat `policy.products` as an override and omit it unless explicitly requested.
- Append new entries unless the user explicitly requests reordering.
- Replace an existing entry for the same plugin only when overwrite is intentional.
- Default new plugin creation to the personal marketplace.
- If the current Git repo already has `.agents/plugins/marketplace.json` and the user has not said
personal or team, ask which marketplace to update before creating the entry.
- Choose marketplace location to match the selected destination:
- Personal plugin: `~/.agents/plugins/marketplace.json`
- Repo/team plugin: `<repo-root>/.agents/plugins/marketplace.json`
22 changes: 16 additions & 6 deletions .agents/skills/plugin-creator/scripts/create_basic_plugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Scaffold a plugin directory and optionally update repo-root marketplace.json."""
"""Scaffold a plugin directory and optionally update marketplace.json."""

from __future__ import annotations

Expand All @@ -11,8 +11,8 @@


MAX_PLUGIN_NAME_LENGTH = 64
DEFAULT_PLUGIN_PARENT = Path(__file__).resolve().parents[4] / "plugins"
DEFAULT_MARKETPLACE_PATH = Path(__file__).resolve().parents[2] / "plugins" / "marketplace.json"
DEFAULT_PLUGIN_PARENT = Path.home() / "plugins"
DEFAULT_MARKETPLACE_PATH = Path.home() / ".agents" / "plugins" / "marketplace.json"
DEFAULT_INSTALL_POLICY = "AVAILABLE"
DEFAULT_AUTH_POLICY = "ON_INSTALL"
DEFAULT_CATEGORY = "Productivity"
Expand Down Expand Up @@ -191,7 +191,10 @@ def parse_args() -> argparse.Namespace:
parser.add_argument(
"--path",
default=str(DEFAULT_PLUGIN_PARENT),
help="Parent directory for plugin creation (defaults to <repo>/plugins)",
help=(
"Parent directory for plugin creation (defaults to <home>/plugins). "
"Use <repo>/plugins when creating a repo/team plugin."
),
)
parser.add_argument("--with-skills", action="store_true", help="Create skills/ directory")
parser.add_argument("--with-hooks", action="store_true", help="Create hooks/ directory")
Expand All @@ -202,12 +205,19 @@ def parse_args() -> argparse.Namespace:
parser.add_argument(
"--with-marketplace",
action="store_true",
help="Create or update repo-root .agents/plugins/marketplace.json",
help=(
"Create or update <home>/.agents/plugins/marketplace.json by default. "
"Marketplace entries always point to ./plugins/<plugin-name> relative to the "
"marketplace root."
),
)
parser.add_argument(
"--marketplace-path",
default=str(DEFAULT_MARKETPLACE_PATH),
help="Path to marketplace.json (defaults to <repo>/.agents/plugins/marketplace.json)",
help=(
"Path to marketplace.json (defaults to <home>/.agents/plugins/marketplace.json). "
"Use <repo>/.agents/plugins/marketplace.json for a repo/team plugin."
),
)
parser.add_argument(
"--install-policy",
Expand Down