# How the validate-plugins GitHub Action Validates Claude Marketplace Plugins

> Learn how the validate-plugins GitHub Action ensures Claude Marketplace plugin safety by orchestrating schema compliance security checks and CLI validation in a reproducible CI pipeline.

- Repository: [Anthropic/claude-plugins-community](https://github.com/anthropics/claude-plugins-community)
- Tags: how-to-guide
- Published: 2026-08-30

---

**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`](https://github.com/anthropics/claude-plugins-community/blob/main/.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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/20-validate-cli-marketplace.sh) script invokes `claude plugin validate` against the assembled [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/marketplace.json) (default: [`.claude-plugin/marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.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`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/validate-plugins.yml) invokes the action with scoped error checking:

```yaml
- 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:

```yaml
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:

```yaml
- 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`](https://github.com/anthropics/claude-plugins-community/blob/main/00-detect-changes.sh), only testing modified entries to optimize CI performance.
- **Policy invariants** (I1-I11) are enforced by [`11-validate-invariants.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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.