How the validate-plugins GitHub Action Validates Claude Marketplace Plugins

The validate-plugins GitHub Action is a composite action that enforces schema compliance, security invariants, and repository policy across the Claude Marketplace by orchestrating change detection, custom invariant checks, and CLI validation in a reproducible CI pipeline.

The validate-plugins GitHub Action serves as the mandatory quality gate for the anthropics/claude-plugins-community repository, ensuring every plugin submission meets Anthropic's strict standards before merging. This composite action executes a multi-step validation pipeline that checks everything from JSON schema conformance to external repository security. Whether you are maintaining the official marketplace or consuming the action in your own plugin registry, understanding its internals helps you debug failures and customize enforcement rules.

Core Validation Pipeline

The action runs nine distinct phases defined in .github/actions/validate-plugins/action.yml, executing shell scripts that progressively validate marketplace integrity.

Environment Setup and Tooling

The action begins by creating a temporary workspace and installing dependencies. It sets environment variables including VALIDATE_TMP and ACTION_PATH, then installs jq, Node.js 20, and the Claude CLI (@anthropic-ai/claude-code). The installation logic includes retry mechanisms (up to three attempts) and forces the optional native binary to be present, ensuring consistent tooling across runner environments.

Change Detection with Git Diff

The scripts/00-detect-changes.sh script computes the delta between the current commit and BASE_REF (defaults to the PR base or origin/main). It outputs three JSON arrays consumed by downstream steps:

  • Changed marketplace entries
  • Changed external plugin references
  • Changed in-repo plugin folders

This selective validation ensures CI time is spent only on modified artifacts.

Custom Invariant Enforcement (I1-I11)

Before schema validation, scripts/11-validate-invariants.sh enforces repository-specific policy rules coded as invariant checks. These include alphabetical name sorting, duplicate name detection, and SHA exemption validations. The action accepts a warn-invariants input (default: "I1 I3 I5 I8") that downgrades specific invariant violations to warnings, while scope-errors-to-changed limits error reporting to modified entries only.

CLI Schema Validation

The scripts/20-validate-cli-marketplace.sh script invokes claude plugin validate against the assembled marketplace.json file. This official Claude CLI command verifies that the manifest conforms to the current marketplace schema, catching structural errors before they reach production.

External Plugin Security Scanning

When skip-external is false, scripts/30-validate-cli-external.sh clones each changed external repository listed in the marketplace, respecting the allowed-hosts whitelist (default: github.com gitlab.com bitbucket.org). It runs the Claude CLI validation against each external plugin with a configurable timeout (external-timeout-secs, default 120 seconds), preventing CI hangs from unresponsive third-party repositories.

Local Folder and Auxiliary File Validation

For in-repo plugins, scripts/40-validate-cli-local.sh validates changed folders within the repository when skip-local-folders is false. Subsequently, scripts/41-validate-aux-files.sh parses auxiliary JSON files accompanying plugin folders to ensure they are well-formed, catching metadata syntax errors that could break marketplace consumers.

Reporting and Exit Conditions

The final step executes scripts/90-report.sh, which aggregates results from all previous phases. It generates a markdown report at the path specified by report-path and sets the result output to "pass" or "fail". The workflow fails if any step returns an error, or if warnings are treated as errors when fail-on-warnings is set to "true".

Configuration Inputs and Outputs

Key Inputs

  • marketplace-path: Path to the assembled marketplace.json (default: .claude-plugin/marketplace.json)
  • entries-dir: Directory containing per-plugin JSON files when using per-file mode (default: "")
  • base-ref: Git reference for change detection (default: ${{ github.event.pull_request.base.sha || github.event.before || 'origin/main' }})
  • warn-invariants: Space-separated invariant codes downgraded to warnings (default: "I1 I3 I5 I8")
  • sha-exempt: Plugin names allowed to omit source.sha (default: "")
  • scope-errors-to-changed: When "true", downgrades invariant errors on unchanged entries to warnings (default: "false")
  • skip-external: Bypass external repository validation (default: "false")
  • skip-local-folders: Bypass in-repo folder validation (default: "false")
  • fail-on-warnings: Treat any warning as a failure (default: "false")
  • validate-all-external: Validate all external entries for nightly drift detection (default: "false")
  • claude-cli-version: Specific Claude CLI version to install (default: latest)
  • external-timeout-secs: Per-plugin clone and validation timeout (default: "120")
  • allowed-hosts: Whitelisted git hosts for external URLs (default: "github.com gitlab.com bitbucket.org")
  • npm-registry: Optional custom npm registry URL (default: "")

Outputs

  • changed-entries: JSON array of marketplace entry names modified in the PR
  • changed-external: JSON array of changed external entries containing name, source, and strictness objects
  • changed-folders: JSON array of modified in-repo plugin folder paths
  • result: Final status string ("pass" or "fail")
  • report-path: Path to the generated markdown summary

Implementation Examples

Basic Repository Workflow

The repository's own validation workflow at .github/workflows/validate-plugins.yml invokes the action with scoped error checking:

- uses: ./.github/actions/validate-plugins
  with:
    marketplace-path: .claude-plugin/marketplace.json
    skip-local-folders: "true"
    scope-errors-to-changed: "true"

Downstream Integration

Third-party repositories can pin to a specific version of the validate-plugins GitHub Action to enforce Claude Marketplace standards:

name: Validate Claude Plugins
on: pull_request

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }

      - uses: anthropics/claude-plugins-community/.github/actions/validate-plugins@v1
        with:
          marketplace-path: .claude-plugin/marketplace.json
          entries-dir: .claude-plugin/plugins
          fail-on-warnings: "true"

Accessing Validation Reports

Capture the markdown report for debugging or audit trails by referencing the output path:

- uses: anthropics/claude-plugins-community/.github/actions/validate-plugins@v1
  id: validation

- name: Upload validation report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: plugin-validation-report
    path: ${{ steps.validation.outputs.report-path }}

Summary

  • The validate-plugins GitHub Action is a composite action composed of sequential shell scripts located in .github/actions/validate-plugins/scripts/.
  • It performs selective validation via 00-detect-changes.sh, only testing modified entries to optimize CI performance.
  • Policy invariants (I1-I11) are enforced by 11-validate-invariants.sh before schema validation occurs.
  • The official Claude CLI (claude plugin validate) provides the authoritative schema checks for both marketplace manifests and individual plugins.
  • External plugin validation includes security controls like host whitelisting (allowed-hosts) and timeout enforcement (external-timeout-secs).
  • Configuration inputs allow flexible enforcement levels, from strict fail-on-warnings modes to scoped error reporting.

Frequently Asked Questions

How does the action determine which plugins to validate?

The scripts/00-detect-changes.sh script compares the current commit against base-ref using git diff, producing JSON arrays of changed marketplace entries, external references, and local folders. This ensures validation runs only against modified artifacts unless validate-all-external is set to "true".

What are the invariant codes (I1-I11) and how do I configure them?

Invariant codes represent repository-specific policy rules, such as alphabetical sorting requirements or SHA presence mandates. You can downgrade specific invariants to warnings using the warn-invariants input (e.g., "I1 I3 I5 I8"), or exempt specific plugins from SHA requirements using the sha-exempt parameter.

Can I use this action to validate plugins in my own repository?

Yes. Reference the action using the full repository path anthropics/claude-plugins-community/.github/actions/validate-plugins@v1 and provide your marketplace-path and optional entries-dir. Ensure you checkout code with fetch-depth: 0 to enable proper change detection.

How does the action handle external repository timeouts?

The 30-validate-cli-external.sh script enforces a per-plugin timeout defaulting to 120 seconds (external-timeout-secs). If cloning or validating an external plugin exceeds this limit, the action marks that plugin as failed and continues processing remaining entries.

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 →