feat: add plugin-create skill and plugin template
Adds the plugin-create skill (.agents/skills/plugin-create/) that scaffolds a new plugin from templates/plugin/, substitutes PLUGIN_NAME/AUTHOR_* markers, registers the plugin in marketplace.json, runs claude plugin validate ., and hands off to /marketplace-architect. Includes evals and the generic template with all components (agents, skills, hooks, MCP, bin, docs) with per-directory READMEs explaining what goes where and which tool reads each directory. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
118
.agents/evals/marketplace/plugin-create/eval.yaml
Normal file
118
.agents/evals/marketplace/plugin-create/eval.yaml
Normal file
@@ -0,0 +1,118 @@
|
||||
skill_name: plugin-create
|
||||
|
||||
trigger_tests:
|
||||
- id: explicit-create-named-plugin
|
||||
name: "Explicit trigger — create named plugin"
|
||||
query: "create a new plugin called security-tools"
|
||||
should_trigger: true
|
||||
|
||||
- id: explicit-scaffold-plugin
|
||||
name: "Explicit trigger — scaffold plugin"
|
||||
query: "scaffold a plugin called developer-tools"
|
||||
should_trigger: true
|
||||
|
||||
- id: implicit-add-marketplace-plugin
|
||||
name: "Implicit trigger — add plugin to marketplace"
|
||||
query: "add a new plugin to the marketplace for developer tools"
|
||||
should_trigger: true
|
||||
|
||||
- id: implicit-package-skills-into-plugin
|
||||
name: "Implicit trigger — package skills into a plugin"
|
||||
query: "I want to package up my skills into a distributable plugin"
|
||||
should_trigger: true
|
||||
|
||||
- id: negative-validate-marketplace
|
||||
name: "Negative trigger — validate marketplace.json (routes to /marketplace-architect)"
|
||||
query: "validate my marketplace.json"
|
||||
should_trigger: false
|
||||
|
||||
- id: negative-write-skill
|
||||
name: "Negative trigger — write a skill (routes to /write-skill)"
|
||||
query: "write a skill for code review"
|
||||
should_trigger: false
|
||||
|
||||
- id: negative-adopt-external-plugin
|
||||
name: "Negative trigger — adopt external plugin (routes to /marketplace-architect)"
|
||||
query: "adopt this external plugin into my marketplace"
|
||||
should_trigger: false
|
||||
|
||||
output_tests:
|
||||
- id: gate-a-shows-plan
|
||||
name: "Gate A presents file list and marketplace entry before writing"
|
||||
type: deterministic
|
||||
prompt: >
|
||||
Create a new plugin called marketplace-tools, description: 'Tools for managing the
|
||||
holocron marketplace', author: Jane Doe, email: jane@example.com,
|
||||
URL: https://github.com/jane
|
||||
expected_output: >
|
||||
The skill presents a plan listing all files that will be written under
|
||||
plugins/marketplace-tools/, shows the new marketplace.json entry, and
|
||||
explicitly asks for approval before writing any file.
|
||||
assertions:
|
||||
- "Output lists files to be written under plugins/marketplace-tools/"
|
||||
- "Output includes a marketplace.json entry with name 'marketplace-tools'"
|
||||
- "Output explicitly asks for approval and does not proceed without it"
|
||||
- "Output does not contain any written file confirmation before approval is given"
|
||||
|
||||
- id: reserved-name-rejected
|
||||
name: "Reserved plugin name is rejected before Gate A"
|
||||
type: deterministic
|
||||
prompt: "Create a new plugin called claude-tools"
|
||||
expected_output: >
|
||||
The skill halts before presenting Gate A, reports that 'claude-tools' matches
|
||||
the reserved name pattern 'claude-*', and asks the user to provide a different name.
|
||||
assertions:
|
||||
- "Output does not present Gate A or a file list"
|
||||
- "Output identifies 'claude-tools' as a reserved name"
|
||||
- "Output asks the user to provide a replacement name before continuing"
|
||||
|
||||
- id: no-skill-stub-generated
|
||||
name: "No skill stub generated — skills/ is empty with README only"
|
||||
type: deterministic
|
||||
prompt: >
|
||||
Create a new plugin called marketplace-tools, description: 'Tools for managing the
|
||||
holocron marketplace', author: Jane Doe, email: jane@example.com,
|
||||
URL: https://github.com/jane. Approve Gate A and Gate B.
|
||||
expected_output: >
|
||||
The plugin scaffold does not include any SKILL.md file. The skills/ directory
|
||||
is present with a README only. The skill directs the user to /write-skill
|
||||
to add skill content.
|
||||
assertions:
|
||||
- "Output does not include creation of any SKILL.md file"
|
||||
- "Output includes a skills/ directory entry with README.md only"
|
||||
- "Output mentions /write-skill for adding skill content"
|
||||
|
||||
- id: handoff-message-present
|
||||
name: "Hand-off message directs user to /marketplace-architect"
|
||||
type: deterministic
|
||||
prompt: >
|
||||
Create a new plugin called marketplace-tools, description: 'Tools for managing the
|
||||
holocron marketplace', author: Jane Doe, email: jane@example.com,
|
||||
URL: https://github.com/jane. Approve Gate A and Gate B.
|
||||
expected_output: >
|
||||
After writing files and running validation, the skill prints a hand-off message
|
||||
that names the created plugin and instructs the user to run /marketplace-architect.
|
||||
assertions:
|
||||
- "Output contains the string '/marketplace-architect'"
|
||||
- "Output includes the plugin name 'marketplace-tools' in the hand-off message"
|
||||
- "Output does not auto-invoke /marketplace-architect itself"
|
||||
|
||||
- id: full-flow-quality
|
||||
name: "Full flow — correct sequencing, substitution, and hand-off"
|
||||
type: llm-rubric
|
||||
prompt: >
|
||||
Create a new plugin called developer-tools with description 'Developer productivity
|
||||
toolkit', author: Alex Smith, email: alex@example.com, URL: https://github.com/alex.
|
||||
Approve Gate A and Gate B.
|
||||
expected_output: >
|
||||
The skill executes the full create-plugin flow: collects all five inputs one at a
|
||||
time, presents Gate A with a file plan, copies and substitutes the template, presents
|
||||
Gate B with full file contents, writes files after Gate B approval, updates
|
||||
marketplace.json, runs validation, and prints a hand-off message.
|
||||
assertions:
|
||||
- "All five inputs (plugin name, description, author name, email, URL) were collected individually before Gate A was presented"
|
||||
- "Gate A clearly listed all files to be written and the new marketplace.json entry, and waited for explicit approval"
|
||||
- "Gate B showed the full substituted content of every file before writing"
|
||||
- "None of the strings PLUGIN_NAME, PLUGIN_DESCRIPTION, AUTHOR_NAME, AUTHOR_EMAIL, or AUTHOR_URL appear in the written file output"
|
||||
- "The validation step either ran claude plugin validate . and reported output, or explicitly stated it was unavailable"
|
||||
- "The final message directed the user to run /marketplace-architect and included the plugin name 'developer-tools'"
|
||||
13
.agents/skills/plugin-create/META.md
Normal file
13
.agents/skills/plugin-create/META.md
Normal file
@@ -0,0 +1,13 @@
|
||||
```yaml
|
||||
version: "1.0"
|
||||
updated: 2026-06-20
|
||||
|
||||
when: Invoked when the user wants to create a new plugin in the marketplace. Scaffolds the
|
||||
directory structure from templates/plugin/, substitutes PLUGIN_NAME/PLUGIN_DESCRIPTION/
|
||||
AUTHOR_NAME/AUTHOR_EMAIL/AUTHOR_URL placeholders, writes to plugins/<name>/, registers
|
||||
the plugin in .claude-plugin/marketplace.json, runs claude plugin validate ., and hands
|
||||
off to /marketplace-architect.
|
||||
|
||||
references:
|
||||
- docs/research/plugin-marketplace-architecture.md
|
||||
```
|
||||
89
.agents/skills/plugin-create/SKILL.md
Normal file
89
.agents/skills/plugin-create/SKILL.md
Normal file
@@ -0,0 +1,89 @@
|
||||
---
|
||||
name: plugin-create
|
||||
description: >
|
||||
Use when the user wants to create a new plugin in the marketplace — scaffold the directory
|
||||
structure, generate plugin.json manifests for Claude Code and Copilot CLI, and register
|
||||
the plugin in marketplace.json. Triggers: "create a new plugin", "add a plugin called X",
|
||||
"scaffold a plugin", "new plugin for Y". Do NOT use when auditing or refactoring existing
|
||||
plugins (use /marketplace-architect), authoring skill content inside a plugin (use
|
||||
/write-skill), adopting an external plugin into the marketplace (use /marketplace-architect),
|
||||
or validating existing manifests without creating anything (use /marketplace-architect).
|
||||
metadata:
|
||||
category: marketplace
|
||||
---
|
||||
|
||||
<requirements>
|
||||
|
||||
## Required inputs
|
||||
|
||||
- **Plugin name** — kebab-case slug; ask if not stated. Validate: lowercase letters, digits, hyphens only; not already present in `plugins/` or `.claude-plugin/marketplace.json`; not a reserved name (`anthropic-*`, `claude-*`, `agent-skills`, `official-claude-plugins`).
|
||||
- **Plugin description** — one sentence; ask if not stated.
|
||||
- **Author name** — ask if not stated.
|
||||
- **Author email** — ask if not stated; used in the Copilot root `plugin.json`.
|
||||
- **Author URL** — ask if not stated; used in Claude's `.claude-plugin/plugin.json`.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Verify `templates/plugin/` exists at the repo root before doing anything — stop if missing; do not generate files from memory.
|
||||
- Plugin name must be kebab-case and not a reserved name (`anthropic-*`, `claude-*`, `agent-skills`, `official-claude-plugins`) — halt and ask for a replacement before Gate A if violated.
|
||||
- Do not write any file until Gate A (plan approval) and Gate B (file contents approval) are both explicitly confirmed.
|
||||
- Replace all five placeholder markers — `PLUGIN_NAME`, `PLUGIN_DESCRIPTION`, `AUTHOR_NAME`, `AUTHOR_EMAIL`, `AUTHOR_URL` — in every copied file before Gate B review. No marker may appear in written output.
|
||||
- Do not generate skill content — `skills/` is scaffolded as an empty directory with README only. Direct the user to `/write-skill` to add skills.
|
||||
- Do not set `version` in both `plugin.json` and the marketplace entry — `plugin.json` wins silently and blocks updates for existing users.
|
||||
- Update `.github/plugin/marketplace.json` only if it already exists — do not create it.
|
||||
- Do not auto-invoke `/marketplace-architect` — hand off by name at the end; let the user trigger it.
|
||||
|
||||
</requirements>
|
||||
|
||||
<steps>
|
||||
|
||||
## Process
|
||||
|
||||
1. **Collect inputs.** Ask for plugin name, description, author name, author email, and author URL — one question at a time. Validate the plugin name: kebab-case format, not a reserved name, not already present in `plugins/` or `.claude-plugin/marketplace.json`. If any validation fails, stop and ask for a replacement before continuing.
|
||||
|
||||
2. **Check template.** Verify `templates/plugin/` exists at the repo root. If missing, stop and report the path — do not proceed or generate files from memory.
|
||||
|
||||
3. **Gate A — plan review.** Present: the list of files that will be written (derived from `templates/plugin/` with `PLUGIN_NAME` substituted into filenames), the new `plugins/<name>/` directory path, the marketplace entry that will be added to `.claude-plugin/marketplace.json`, and whether `.github/plugin/marketplace.json` will also be updated. Wait for explicit approval — do not proceed on "looks good" or silence.
|
||||
|
||||
4. **Copy and substitute.** Copy `templates/plugin/` to `plugins/<name>/`. In every copied file, replace all occurrences of `PLUGIN_NAME`, `PLUGIN_DESCRIPTION`, `AUTHOR_NAME`, `AUTHOR_EMAIL`, and `AUTHOR_URL` with the collected values. Rename any file or directory whose name contains `PLUGIN_NAME`.
|
||||
|
||||
5. **Gate B — file contents review.** Show every file with its full substituted content. Wait for explicit approval — do not write until confirmed.
|
||||
|
||||
6. **Write files.** Write all substituted files to `plugins/<name>/`. Append the new plugin entry to `.claude-plugin/marketplace.json`. If `.github/plugin/marketplace.json` exists, append the same entry there.
|
||||
|
||||
7. **Validate.** Run `claude plugin validate .` from `plugins/<name>/`. Report all output inline — do not suppress warnings. If the command is unavailable, note it and suggest the user run it manually after local install.
|
||||
|
||||
8. **Hand off.** Print: "Plugin `<name>` created and registered in `marketplace.json`. Fill in skill and agent content, then run `/marketplace-architect` to audit the full marketplace."
|
||||
|
||||
## Output format
|
||||
|
||||
- `plugins/<name>/` — directory tree copied from `templates/plugin/` with all placeholders substituted
|
||||
- `.claude-plugin/marketplace.json` — updated with the new plugin entry
|
||||
- `.github/plugin/marketplace.json` — updated with the same entry, only if it already existed
|
||||
- Inline validation report from `claude plugin validate .`
|
||||
|
||||
</steps>
|
||||
|
||||
<checks>
|
||||
|
||||
## Failure handling
|
||||
|
||||
- `templates/plugin/` not found — stop, report the path searched, do not generate from memory.
|
||||
- Plugin name already exists in `plugins/` or `marketplace.json` — stop, report the conflict, ask for a different name.
|
||||
- Reserved name detected — stop, report the name and the reserved list, ask for a replacement before continuing.
|
||||
- `claude plugin validate .` unavailable — report that automated validation was skipped; suggest running it manually with `claude --plugin-dir ./plugins/<name>`.
|
||||
|
||||
## Self-check
|
||||
|
||||
- [ ] Plugin name validated: kebab-case, not reserved, not already present in `plugins/` or `marketplace.json`
|
||||
- [ ] `templates/plugin/` verified to exist before any file generation
|
||||
- [ ] Gate A presented with file list and marketplace entry — explicit approval received
|
||||
- [ ] All five markers substituted in all files — none appear in written output
|
||||
- [ ] Gate B presented with full substituted file contents — explicit approval received
|
||||
- [ ] Files written only after Gate B approval
|
||||
- [ ] `.github/plugin/marketplace.json` updated only if it already existed — not created
|
||||
- [ ] `claude plugin validate .` run and results reported; or unavailability noted
|
||||
- [ ] Hand-off message printed directing user to `/marketplace-architect`
|
||||
- [ ] No skill content generated — `skills/` is empty with README only
|
||||
|
||||
</checks>
|
||||
8
templates/plugin/.claude-plugin/plugin.json
Normal file
8
templates/plugin/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "PLUGIN_NAME",
|
||||
"displayName": "PLUGIN_NAME",
|
||||
"description": "PLUGIN_DESCRIPTION",
|
||||
"author": { "name": "AUTHOR_NAME", "url": "AUTHOR_URL" },
|
||||
"license": "MIT",
|
||||
"keywords": []
|
||||
}
|
||||
3
templates/plugin/.mcp.json
Normal file
3
templates/plugin/.mcp.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"mcpServers": {}
|
||||
}
|
||||
42
templates/plugin/README.md
Normal file
42
templates/plugin/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# PLUGIN_NAME
|
||||
|
||||
PLUGIN_DESCRIPTION
|
||||
|
||||
## Install
|
||||
|
||||
**Claude Code:**
|
||||
|
||||
```bash
|
||||
claude plugin marketplace add <owner>/<repo>
|
||||
claude plugin install PLUGIN_NAME@<marketplace-name>
|
||||
```
|
||||
|
||||
**GitHub Copilot CLI:**
|
||||
|
||||
```bash
|
||||
copilot plugin marketplace add <owner>/<repo>
|
||||
copilot plugin install PLUGIN_NAME
|
||||
```
|
||||
|
||||
**Local (development):**
|
||||
|
||||
```bash
|
||||
# Claude Code
|
||||
claude --plugin-dir ./plugins/PLUGIN_NAME
|
||||
|
||||
# GitHub Copilot CLI
|
||||
copilot plugin install ./plugins/PLUGIN_NAME
|
||||
```
|
||||
|
||||
## Contents
|
||||
|
||||
| Component | Path | Description |
|
||||
|---|---|---|
|
||||
| Skills | `skills/` | Slash commands available after install |
|
||||
| Agents | `agents/` | Role-based agents (`.md` for Claude, `.agent.md` for Copilot) |
|
||||
| Hooks | `hooks/hooks.json` (Claude) / `hooks.json` (Copilot) | Event-triggered automation |
|
||||
| MCP servers | `.mcp.json` | Model Context Protocol server definitions |
|
||||
|
||||
## Author
|
||||
|
||||
AUTHOR_NAME
|
||||
13
templates/plugin/agents/PLUGIN_NAME.agent.md
Normal file
13
templates/plugin/agents/PLUGIN_NAME.agent.md
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
name: PLUGIN_NAME
|
||||
description: PLUGIN_DESCRIPTION
|
||||
tools:
|
||||
- read_file
|
||||
- list_directory
|
||||
---
|
||||
|
||||
Replace this with your agent's system prompt and instructions.
|
||||
|
||||
This file is loaded by **GitHub Copilot CLI**. The `tools:` frontmatter field declares
|
||||
which tools the agent can use — add or remove tools as needed.
|
||||
For Claude Code, see `PLUGIN_NAME.md`.
|
||||
8
templates/plugin/agents/PLUGIN_NAME.md
Normal file
8
templates/plugin/agents/PLUGIN_NAME.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
name: PLUGIN_NAME
|
||||
description: PLUGIN_DESCRIPTION
|
||||
---
|
||||
|
||||
Replace this with your agent's system prompt and instructions.
|
||||
|
||||
This file is loaded by **Claude Code**. For GitHub Copilot CLI, see `PLUGIN_NAME.agent.md`.
|
||||
13
templates/plugin/agents/README.md
Normal file
13
templates/plugin/agents/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# agents/
|
||||
|
||||
Agent definitions for this plugin. Each agent needs two files — one per tool:
|
||||
|
||||
| File | Tool | Notes |
|
||||
|---|---|---|
|
||||
| `<name>.md` | Claude Code | Frontmatter: `name`, `description`. No `tools:` field. |
|
||||
| `<name>.agent.md` | GitHub Copilot CLI | Frontmatter: `name`, `description`, `tools:` (array of permitted tool names). |
|
||||
|
||||
The two files share the same system prompt body. Keep them in sync.
|
||||
|
||||
Rename `PLUGIN_NAME.md` and `PLUGIN_NAME.agent.md` to your agent's name (kebab-case).
|
||||
Add additional agent pairs as needed — one pair per agent.
|
||||
11
templates/plugin/bin/README.md
Normal file
11
templates/plugin/bin/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# bin/
|
||||
|
||||
**Claude Code only.** Executables placed here are added to PATH when the plugin is installed.
|
||||
|
||||
Use this for CLI tools, helper scripts, or MCP server entry points bundled with the plugin.
|
||||
|
||||
Reference files in this directory from `.mcp.json` or hooks using `${CLAUDE_PLUGIN_ROOT}/bin/<file>`.
|
||||
The `${CLAUDE_PLUGIN_ROOT}` variable resolves to the plugin's install cache path at runtime —
|
||||
do not use relative paths from the repo root, as they will break after install.
|
||||
|
||||
GitHub Copilot CLI does not support `bin/`. If you add executables here, they are Claude Code only.
|
||||
7
templates/plugin/docs/README.md
Normal file
7
templates/plugin/docs/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# docs/
|
||||
|
||||
Plugin documentation. Place usage guides, reference material, and examples here.
|
||||
|
||||
This directory is not read automatically by either Claude Code or GitHub Copilot CLI.
|
||||
Reference specific files from your skill bodies or agent prompts when needed
|
||||
(e.g. `See references/usage.md for examples`).
|
||||
3
templates/plugin/hooks.json
Normal file
3
templates/plugin/hooks.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"hooks": []
|
||||
}
|
||||
27
templates/plugin/hooks/README.md
Normal file
27
templates/plugin/hooks/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# hooks/
|
||||
|
||||
**Claude Code only.** Hook definitions that run in response to Claude Code events.
|
||||
|
||||
The `hooks.json` in this directory is read by Claude Code. Structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{ "type": "command", "command": "echo 'tool used'" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Supported events: `PreToolUse`, `PostToolUse`, `Notification`, `Stop`.
|
||||
|
||||
Use `${CLAUDE_PLUGIN_ROOT}` to reference scripts inside this plugin — the plugin runs
|
||||
from a cache path after install, not its original repo location.
|
||||
|
||||
For GitHub Copilot CLI hooks, see `hooks.json` at the plugin root.
|
||||
3
templates/plugin/hooks/hooks.json
Normal file
3
templates/plugin/hooks/hooks.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"hooks": {}
|
||||
}
|
||||
11
templates/plugin/plugin.json
Normal file
11
templates/plugin/plugin.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "PLUGIN_NAME",
|
||||
"description": "PLUGIN_DESCRIPTION",
|
||||
"author": { "name": "AUTHOR_NAME", "email": "AUTHOR_EMAIL" },
|
||||
"license": "MIT",
|
||||
"keywords": [],
|
||||
"agents": "agents/",
|
||||
"skills": ["skills/"],
|
||||
"hooks": "hooks.json",
|
||||
"mcpServers": ".mcp.json"
|
||||
}
|
||||
18
templates/plugin/skills/README.md
Normal file
18
templates/plugin/skills/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# skills/
|
||||
|
||||
Skills for this plugin. Each skill lives in its own subdirectory:
|
||||
|
||||
```
|
||||
skills/
|
||||
<skill-name>/
|
||||
SKILL.md # required — frontmatter + skill body
|
||||
META.md # required — provenance and audit fields
|
||||
references/ # optional — on-demand reference docs
|
||||
scripts/ # optional — executable helper scripts
|
||||
assets/ # optional — templates, data files, lookup tables
|
||||
```
|
||||
|
||||
**Shared** — both Claude Code and GitHub Copilot CLI read `skills/<name>/SKILL.md`.
|
||||
|
||||
To add a skill, run `/write-skill` in a Claude Code session. Do not write SKILL.md by hand
|
||||
without following the authoring standard — trigger descriptions and self-checks are required.
|
||||
Reference in New Issue
Block a user