diff --git a/.agents/evals/marketplace/plugin-create/eval.yaml b/.agents/evals/marketplace/plugin-create/eval.yaml new file mode 100644 index 0000000..bac5c8c --- /dev/null +++ b/.agents/evals/marketplace/plugin-create/eval.yaml @@ -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'" diff --git a/.agents/skills/plugin-create/META.md b/.agents/skills/plugin-create/META.md new file mode 100644 index 0000000..648f1e9 --- /dev/null +++ b/.agents/skills/plugin-create/META.md @@ -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//, 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 +``` diff --git a/.agents/skills/plugin-create/SKILL.md b/.agents/skills/plugin-create/SKILL.md new file mode 100644 index 0000000..d0363db --- /dev/null +++ b/.agents/skills/plugin-create/SKILL.md @@ -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 +--- + + + +## 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. + + + + + +## 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//` 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//`. 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//`. 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//`. 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 `` created and registered in `marketplace.json`. Fill in skill and agent content, then run `/marketplace-architect` to audit the full marketplace." + +## Output format + +- `plugins//` — 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 .` + + + + + +## 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/`. + +## 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 + + diff --git a/templates/plugin/.claude-plugin/plugin.json b/templates/plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..5ce673d --- /dev/null +++ b/templates/plugin/.claude-plugin/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "PLUGIN_NAME", + "displayName": "PLUGIN_NAME", + "description": "PLUGIN_DESCRIPTION", + "author": { "name": "AUTHOR_NAME", "url": "AUTHOR_URL" }, + "license": "MIT", + "keywords": [] +} diff --git a/templates/plugin/.mcp.json b/templates/plugin/.mcp.json new file mode 100644 index 0000000..da39e4f --- /dev/null +++ b/templates/plugin/.mcp.json @@ -0,0 +1,3 @@ +{ + "mcpServers": {} +} diff --git a/templates/plugin/README.md b/templates/plugin/README.md new file mode 100644 index 0000000..6b69dcd --- /dev/null +++ b/templates/plugin/README.md @@ -0,0 +1,42 @@ +# PLUGIN_NAME + +PLUGIN_DESCRIPTION + +## Install + +**Claude Code:** + +```bash +claude plugin marketplace add / +claude plugin install PLUGIN_NAME@ +``` + +**GitHub Copilot CLI:** + +```bash +copilot plugin marketplace add / +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 diff --git a/templates/plugin/agents/PLUGIN_NAME.agent.md b/templates/plugin/agents/PLUGIN_NAME.agent.md new file mode 100644 index 0000000..84c6e30 --- /dev/null +++ b/templates/plugin/agents/PLUGIN_NAME.agent.md @@ -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`. diff --git a/templates/plugin/agents/PLUGIN_NAME.md b/templates/plugin/agents/PLUGIN_NAME.md new file mode 100644 index 0000000..a7d3a97 --- /dev/null +++ b/templates/plugin/agents/PLUGIN_NAME.md @@ -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`. diff --git a/templates/plugin/agents/README.md b/templates/plugin/agents/README.md new file mode 100644 index 0000000..c59199a --- /dev/null +++ b/templates/plugin/agents/README.md @@ -0,0 +1,13 @@ +# agents/ + +Agent definitions for this plugin. Each agent needs two files — one per tool: + +| File | Tool | Notes | +|---|---|---| +| `.md` | Claude Code | Frontmatter: `name`, `description`. No `tools:` field. | +| `.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. diff --git a/templates/plugin/bin/README.md b/templates/plugin/bin/README.md new file mode 100644 index 0000000..7399e35 --- /dev/null +++ b/templates/plugin/bin/README.md @@ -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/`. +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. diff --git a/templates/plugin/docs/README.md b/templates/plugin/docs/README.md new file mode 100644 index 0000000..c2dc27a --- /dev/null +++ b/templates/plugin/docs/README.md @@ -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`). diff --git a/templates/plugin/hooks.json b/templates/plugin/hooks.json new file mode 100644 index 0000000..b9820d5 --- /dev/null +++ b/templates/plugin/hooks.json @@ -0,0 +1,3 @@ +{ + "hooks": [] +} diff --git a/templates/plugin/hooks/README.md b/templates/plugin/hooks/README.md new file mode 100644 index 0000000..76d8625 --- /dev/null +++ b/templates/plugin/hooks/README.md @@ -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. diff --git a/templates/plugin/hooks/hooks.json b/templates/plugin/hooks/hooks.json new file mode 100644 index 0000000..deffac9 --- /dev/null +++ b/templates/plugin/hooks/hooks.json @@ -0,0 +1,3 @@ +{ + "hooks": {} +} diff --git a/templates/plugin/plugin.json b/templates/plugin/plugin.json new file mode 100644 index 0000000..157ba61 --- /dev/null +++ b/templates/plugin/plugin.json @@ -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" +} diff --git a/templates/plugin/skills/README.md b/templates/plugin/skills/README.md new file mode 100644 index 0000000..20d05b9 --- /dev/null +++ b/templates/plugin/skills/README.md @@ -0,0 +1,18 @@ +# skills/ + +Skills for this plugin. Each skill lives in its own subdirectory: + +``` +skills/ + / + 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//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.