How to Validate Plugins in the PM Skills Marketplace: Complete Technical Guide

The PM Skills marketplace includes a built-in Python validator (validate_plugins.py) that automatically checks every plugin against the Claude Code specification by verifying manifests, skills, commands, READMEs, and cross-references.

The phuryn/pm-skills repository maintains a collection of plugins for the PM Skills marketplace, each requiring strict adherence to the Claude Code plugin specification. To ensure quality and consistency, the repository includes validate_plugins.py, a comprehensive validation script that inspects every .claude-plugin/ directory against five critical criteria before publication.

Understanding the Five Validation Layers

The validator organizes its checks into five logical sections, each handled by a dedicated function in validate_plugins.py.

1. Manifest Validation (plugin.json)

The validate_manifest() function (lines 16–53) checks that every plugin contains a .claude-plugin/plugin.json file with the required schema. It verifies that required fields (name, version, description) are present, that the version follows semantic versioning, and that the name value matches the directory name. The validator also reports on optional fields including author, keywords, homepage, and license.

2. Skills Validation (SKILL.md)

Each skill folder must contain a SKILL.md file with a YAML front-matter block. The validate_skill() function (lines 82–130) confirms that the front-matter includes name and description fields, that the skill name matches the folder name, and that the description meets minimum length requirements. The function also inspects the file-wide word count to ensure adequate documentation.

3. Commands Validation

Command definitions live in markdown files within the plugin structure. The validate_command() function (lines 32–55) validates that each command file contains a front-matter block with at least a description field. It reports the presence of optional fields like argument-hint and extracts any "skill-name skill" references for later cross-referencing against actual skill folders.

4. README Validation

Every plugin must provide a top-level README.md. The validate_readme() function (lines 68–85) checks for the file's existence and validates that it contains four expected sections: overview, install, skill, and command. Missing sections are reported as warnings or informational notes.

5. Cross-Reference Validation

Commands that invoke skills must reference valid, existing skill folders. The validate_cross_references() function (lines 89–108) compares skill references found in command files against the actual list of skill folder names discovered within the same plugin, flagging any dangling references.

Running the Validator Locally

Invoke the validator from the repository root to check the entire plugin collection:

python ./validate_plugins.py

The script determines the base directory (defaulting to the location of validate_plugins.py), scans for directories containing .claude-plugin/ subdirectories, and executes all five validators for each plugin found. Output includes color-coded errors, warnings, and informational notes organized by plugin:


 Plugin Collection Validator — Report
 ────────────────────────────────────────────────────────────────────────
 plugin‑name  [12 skills, 8 commands]  ✗ FAIL (3 warnings)
   Manifest:
       ✗ ERROR: Missing required field: version
       ⚠ WARN: Missing recommended field: author
   Skills with issues:
       my‑skill:
           ⚠ WARN: Description is very short (28 chars)
   Commands with issues:
       my‑command.md:
           ⚠ WARN: Missing recommended frontmatter field: argument-hint
   README:
       ℹ README may be missing 'install' section
   Cross-references:
       ⚠ WARN: Command my‑command.md references skill 'unknown‑skill' not found in this plugin

The script exits with status 0 on success or non-zero if any errors are detected, making it suitable for automated quality gates.

CI/CD Integration

Because the validator is pure Python and requires only file system access, it integrates seamlessly into continuous integration pipelines. Add the following GitHub Actions workflow to automatically validate plugins on every push or pull request:

name: Plugin validation
on: [push, pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - name: Run validator
        run: python ./validate_plugins.py

If any plugin fails validation—such as missing a required field in plugin.json or referencing a non-existent skill—the job fails automatically, preventing invalid code from merging.

Accessing Validation Results Programmatically

For custom dashboards or build systems, import the validation logic directly into Python code. The module exposes functions that return structured ValidationResult objects:

from validate_plugins import validate_plugin

result = validate_plugin("./pm-toolkit")

# result is a dict with nested ValidationResult objects

print(result["sections"]["manifest"].errors)      # → ['Missing required field: version']

print(result["sections"]["skills"]["grammar-check"].warnings)  # → []

This programmatic interface allows you to build custom reporting tools or integrate validation into larger automated workflows beyond the command-line interface.

Summary

  • The validator (validate_plugins.py) is the official tool for checking PM Skills marketplace plugins against the Claude Code specification.
  • Five validation layers cover manifest files (plugin.json), skill documentation (SKILL.md), command definitions, README completeness, and cross-reference integrity.
  • Local execution requires only Python and the repository checkout; run python ./validate_plugins.py from the repository root.
  • CI integration is straightforward via standard Python setup actions, with automatic non-zero exit codes on validation failures.
  • Programmatic access allows importing validation functions for custom tooling and dashboards.

Frequently Asked Questions

What triggers the validator to recognize a directory as a plugin?

The validator scans for any directory containing a .claude-plugin/ subdirectory. Inside that directory, it expects to find a plugin.json manifest file. This structure indicates to the main() workflow in validate_plugins.py that the folder contains a valid plugin candidate for validation.

What happens if a plugin fails validation?

When validation errors are detected, the script prints a detailed report highlighting each issue—categorized as errors, warnings, or informational notes—and exits with a non-zero status code. This behavior ensures that CI pipelines halt the build process, preventing invalid plugins from being published or merged into the main branch.

Can I validate a single plugin instead of the entire collection?

Yes. While the default main() function discovers all plugins in the repository tree, you can import the validate_plugin() function directly and pass a specific path to a single plugin directory. This allows targeted validation during development without checking the entire marketplace collection.

Which Python version is required to run the validator?

The validator runs on standard Python 3. The CI examples specify Python 3.12, but the script uses only standard library modules for file system operations and JSON/YAML parsing, making it compatible with most modern Python 3 environments without additional dependencies.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →