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
- If
$ARGUMENTSprovides a plugin name, use it to seed Phase 1 - 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 - plugin.json Template & Minimal Metadata Standard (MANDATORY — do not skip):
- Ensure
.claude-plugin/plugin.jsonuses the clean, minimal metadata format:{ "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.jsonmust NEVER containskills,agents,hooks, orcommandsarrays (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.
- Ensure
- plugin.yaml (Hermes compatibility — always generate): After
plugin.jsonis finalized, scaffold aplugin.yamlat the plugin root for hermes-agent compatibility. Format: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-namekind: standalone— plugin has no Python scripts that hermes calls directlykind: backend— plugin has scripts inscripts/that hermes invokes as tools- Only include
provides_toolsifscripts/contains callable tool scripts - Skills list must match actual directory names under
skills/ - Report: "
plugin.yamlcreated for hermes compatibility. ✅"
__init__.py(Hermes tool/hook wiring — generate when plugin has scripts): If the plugin has callable Python scripts inscripts/, scaffold a root-level__init__.pywith aregister(ctx)function following this pattern: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__.pycreated with register() function. ✅"
- Always include
- 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
$ARGUMENTSis 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-integrationfor each one - After scaffolding: run
/agent-scaffolders:audit-pluginto 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:
# 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:
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:
- Scaffold
.claude-plugin/plugin.jsoninside the plugin directory (this skill does this by default) - When adding the plugin to a marketplace entry, explicitly set
"strict": true— never rely on the default - See
manage-marketplaceskill 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 ownscripts/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.