create-plugin · git:20260907.506f5de · 2026-09-07 · sha256 5f25d282c2fb0fa2

create-plugin git:20260907.506f5deA

Immutable. This exact content is served forever at /api/v1/blob/5f25d282c2fb0fa2.

---
name: create-plugin
plugin: agent-scaffolders
description: >
  Scaffolds a new top-level agent plugin directory. NOT for scaffolding single skills (use `create-skill`) and NOT for adding MCP integrations to existing plugins (use `create-mcp-integration`).
argument-hint: "[plugin-name]"
allowed-tools: Bash, Read, Write
---

Follow the `create-plugin` skill workflow to scaffold a new Claude Code plugin.

## Inputs

- `$ARGUMENTS` — optional plugin name in kebab-case. Omit to start with discovery.

## Steps

1. If `$ARGUMENTS` provides a plugin name, use it to seed Phase 1
2. Follow the create-plugin phased workflow: discover purpose and plugin type,
   plan component table (skills / commands / agents / hooks / MCP), ask clarifying
   questions per component, scaffold directory structure and `plugin.json` (ensuring `"author"` is an object with `"name"` and `"email"`), implement
   each component using the appropriate sub-skill, validate, test, and document
3. **plugin.json Template & Minimal Metadata Standard (MANDATORY — do not skip):**
   - Ensure `.claude-plugin/plugin.json` uses the clean, minimal metadata format:
     ```json
     {
       "name": "<plugin-name>",
       "version": "0.1.0",
       "description": "<description>",
       "author": {
         "name": "richfrem",
         "email": "connect.richfrem@gmail.com"
       },
       "repository": "https://github.com/richfrem/agent-plugins-skills",
       "license": "MIT",
       "keywords": [
         "<keyword>"
       ]
     }
     ```
   - **Strict Rules**:
     - `.claude-plugin/plugin.json` must **NEVER** contain `skills`, `agents`, `hooks`, or `commands` arrays (these are auto-discovered by Claude Code).
     - `"author"` must **ALWAYS** be an object with `"name"` (and optionally `"email"`), never a plain string.
     - No duplicate top-level keys.
4. **plugin.yaml (Hermes compatibility — always generate):** After `plugin.json` is finalized, scaffold a `plugin.yaml` at the plugin root for hermes-agent compatibility. Format:
   ```yaml
   name: <plugin-name>
   version: <version>
   description: "<description>"
   author: <author>
   kind: backend  # or standalone (no Python scripts)
   platforms:
     - linux
     - macos
     - windows
   provides_tools:          # list script basenames (no .py) that expose callable tools
     - script_name
   skills:                  # list skill directory names under skills/
     - skill-name
   ```
   - `kind: standalone` — plugin has no Python scripts that hermes calls directly
   - `kind: backend` — plugin has scripts in `scripts/` that hermes invokes as tools
   - Only include `provides_tools` if `scripts/` contains callable tool scripts
   - Skills list must match actual directory names under `skills/`
   - Report: *"`plugin.yaml` created for hermes compatibility. ✅"*
5. **`__init__.py` (Hermes tool/hook wiring — generate when plugin has scripts):** If the plugin has callable Python scripts in `scripts/`, scaffold a root-level `__init__.py` with a `register(ctx)` function following this pattern:
   ```python
   from __future__ import annotations
   from pathlib import Path

   _HERE = Path(__file__).resolve().parent

   def register(ctx) -> None:
       # Register skills
       ctx.register_skill(
           name="<skill-name>",   # bare name only — hermes auto-prefixes plugin name as namespace
           path=_HERE / "skills" / "<skill-name>",
       )
       # Register tools (if scripts expose callable tools)
       # ctx.register_tool(name, toolset, schema, handler)
       # Register hooks (if plugin needs lifecycle hooks)
       # ctx.register_hook("post_tool_call", handler)
   ```
   - Always include `register_skill()` calls for every skill in the plugin
   - Only add `register_tool()` if the plugin provides callable Python tools
   - Only add `register_hook()` if the plugin needs lifecycle hooks
   - Without `__init__.py`, hermes shows "No `__init__.py`" warning and the plugin won't activate
   - Report: *"`__init__.py` created with register() function. ✅"*
6. Report the created plugin directory and verification checklist results

## Output

Plugin directory with `.claude-plugin/plugin.json`, component directories, `README.md`,
and a `.claude/settings.json` stub for reliable local discovery.

## Edge Cases

- If `$ARGUMENTS` is empty: begin with Phase 1 discovery — do not pre-fill plugin name
- If similar plugin already exists: reference it as a starting point
- If MCP integrations are needed: invoke `create-mcp-integration` for each one
- After scaffolding: run `/agent-scaffolders:audit-plugin` to validate structure

## Symlink Standards for Shared Scripts

When a skill needs to call a Python helper script that is shared across skills in the same
plugin, always create a **file-level symlink** in the skill's `scripts/` folder pointing to the
canonical copy at the plugin root — never duplicate the file.

**Standard pattern:**
```
plugins/<plugin>/scripts/<canonical_name>.py      ← canonical source (real file)
plugins/<plugin>/skills/<skill>/scripts/<name>.py  ← symlink → ../../../scripts/<canonical_name>.py
```

The symlink name and target name may differ (e.g. `execute.py` → `exploration_optimizer_execute.py`).
The bridge installer resolves all symlinks to physical copies when deploying via the marketplace.

**Creating symlinks correctly:**
```bash
# From the skill's scripts/ directory:
ln -s ../../../scripts/<canonical_name>.py <symlink_name>.py

# Or via symlink_manager.py:
python plugins/dev-utils/scripts/symlink_manager.py create \
  --src plugins/<plugin>/scripts/<canonical_name>.py \
  --dst plugins/<plugin>/skills/<skill>/scripts/<symlink_name>.py
```

**⚠️ Windows / core.symlinks warning:** If `git config core.symlinks` is `false`, git checks
out symlinks as plain-text "stand-in" files. These are silently broken — the bridge installer
copies the path string, not the script. After checkout on Windows or any machine where
symlinks may have degraded, run:
```bash
python plugins/dev-utils/scripts/bulk_symlink_fixer.py plugins/<plugin-name>
```
Then manually verify: `find plugins/<plugin-name>/skills -path "*/scripts/*" -type f ! -type l`
should return nothing (all script references should be real symlinks, not plain files).

## Marketplace Compatibility Note

When this plugin will be distributed via a `marketplace.json`, the marketplace entry defaults to `strict: true`, which **requires** the plugin to have its own `plugin.json`. A missing `plugin.json` silently prevents the entire plugin from loading.

Always:
1. Scaffold `.claude-plugin/plugin.json` inside the plugin directory (this skill does this by default)
2. When adding the plugin to a marketplace entry, explicitly set `"strict": true` — never rely on the default
3. See `manage-marketplace` skill for the correct marketplace entry format

## Plugin Architecture Conventions

- **Hub-and-spoke shared scripts:** a script used by two or more skills within the same plugin belongs at the plugin root (`scripts/script.py`), not duplicated per-skill. A script used by only one skill lives inside that skill's own `scripts/` directory.
- **No cross-plugin script imports:** a plugin must never import or execute another plugin's Python code directly. Cross-plugin coordination happens via agent delegation (natural-language instructions to invoke another skill), never hardcoded imports.
- **File-level symlinks only, never directories:** shared resources are mirrored into each consuming skill via a real file-level symlink, never a directory-level symlink or a duplicated copy.
- **Self-contained installed skills:** an installed skill must function correctly with zero runtime dependency on the source repository, another plugin, or a sibling Python package.