# How the `validate-plugins` GitHub Action Works in the Claude Plugins Community

> Discover how the validate-plugins GitHub Action in anthropics/claude-plugins-community automatically validates plugin manifests, enforces policies, and tests plugins on every PR and push.

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

---

The `validate-plugins` GitHub Action automatically validates plugin manifests, enforces policy invariants, and tests both internal and external plugins on every pull request or push that touches plugin-related files in the **anthropics/claude-plugins-community** repository.

This composite action serves as the gatekeeper for the Claude plugin ecosystem, ensuring that every submission meets strict quality and security standards before merging. Built with resilience and selective validation in mind, it leverages the authoritative Claude CLI as its schema validator while implementing custom invariant checks for community-specific policies.

## Architecture Overview

The validation system consists of three interconnected layers that work together to provide comprehensive plugin verification.

| Component | Role | Source |
|-----------|------|--------|
| **Workflow definition** | Triggers the pipeline on PRs, pushes, and manual dispatches | [`.github/workflows/validate-plugins.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/validate-plugins.yml) |
| **Composite action** | Packages all validation logic into a reusable, configurable step | [`.github/actions/validate-plugins/action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/action.yml) |
| **Helper scripts** | Bash implementations of each validation stage | `.github/actions/validate-plugins/scripts/*.sh` |

### Workflow Triggers

The workflow defined in [`.github/workflows/validate-plugins.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/validate-plugins.yml) activates on three conditions:

- **Pull requests** modifying `.claude-plugin/**` or `.github/actions/**`
- **Direct pushes** to `main` affecting those same paths
- **Manual dispatch** via `workflow_dispatch` (used by automated SHA-bumping jobs)

The checkout step uses `fetch-depth: 0` to obtain complete Git history, enabling accurate change detection across commits.

### Pre-Composite Static Tests

Before invoking the composite action, the workflow runs several lightweight validation scripts:

| Script | Purpose |
|--------|---------|
| [`test-invariants.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/test-invariants.sh) | Repository-level constraints (required files, naming conventions) |
| [`test-bump.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/test-bump.sh) / [`test-bump-manifest.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/test-bump-manifest.sh) | Verify automated SHA-bumping integrity |
| [`test-sweep.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/test-sweep.sh) | Confirm plugin owners remain reachable |
| [`test-external-manifest.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/test-external-manifest.sh) | Validate external plugin references resolve correctly |
| [`test-pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/test-pin-check.sh) | Ensure pinned versions match expected golden vectors |

## Composite Action Execution Flow

The core validation logic resides in [`.github/actions/validate-plugins/action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/action.yml). When invoked, it executes eight sequential stages:

### 1. Environment Setup

Creates temporary directories, installs `jq`, configures Node 20, and makes all helper scripts executable.

### 2. CLI Installation with Resilience

Installs `@anthropic-ai/claude-code` with robust retry logic and post-install healing to guarantee the `claude` binary is functional, even when network conditions are unstable.

### 3. Change Detection ([`00-detect-changes.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/00-detect-changes.sh))

Builds three JSON arrays that drive selective validation:

```json
{
  "changed-entries": ["plugin-name-1", "plugin-name-2"],
  "changed-external": [{"name": "...", "source": "...", "strict": true}],
  "changed-folders": [".claude-plugin/plugins/plugin-name-1"]
}

```

These arrays enable **scoped validation**—only testing what actually changed rather than the entire marketplace.

### 4. Custom Invariant Checking ([`11-validate-invariants.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/11-validate-invariants.sh))

Implements eleven policy rules (I1–I11) including:

- **I1**: Alphabetical ordering of entries
- **I3**: Required field presence
- **I5**: SHA pinning requirements (with exemptions via `sha-exempt`)
- **I8**: Naming convention enforcement

Violations can be downgraded to warnings via the `warn-invariants` input.

### 5. Marketplace CLI Validation ([`20-validate-cli-marketplace.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/20-validate-cli-marketplace.sh))

Runs `claude plugin validate` against the assembled [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/marketplace.json), using the official Claude CLI as the source-of-truth schema validator.

### 6. External Plugin Validation ([`30-validate-cli-external.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/30-validate-cli-external.sh))

For each changed external entry (or all entries if `validate-all-external: true`):

1. Clones the remote repository
2. Validates against the CLI schema
3. Respects per-plugin timeout (`external-timeout-secs`, default 120 seconds)
4. Enforces host whitelist (`allowed-hosts`: `github.com gitlab.com bitbucket.org`)

### 7. Local Folder Validation ([`40-validate-cli-local.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/40-validate-cli-local.sh))

Validates in-repo plugin folders using the same CLI schema, plus [`41-validate-aux-files.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/41-validate-aux-files.sh) for auxiliary JSON parsing.

### 8. Report Generation ([`90-report.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/90-report.sh))

Aggregates all warnings and errors into a markdown report, then sets the composite outputs:
- `result`: `"pass"` or `"fail"`
- `report-path`: location of the detailed report

## Key Configuration Options

### Inputs

| Input | Description | Default |
|-------|-------------|---------|
| `marketplace-path` | Path to [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/marketplace.json) | [`.claude-plugin/marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/marketplace.json) |
| `base-ref` | Git ref for diff detection | PR base sha, `github.event.before`, or `origin/main` |
| `warn-invariants` | Invariants treated as warnings | `I1 I3 I5 I8` |
| `scope-errors-to-changed` | Downgrade errors on unchanged entries | `false` |
| `skip-external` / `skip-local-folders` | Disable validation categories | `false` |
| `fail-on-warnings` | Treat warnings as failures | `false` |
| `validate-all-external` | Validate all externals, not just changed | `false` |
| `claude-cli-version` | CLI version to install | `latest` |
| `external-timeout-secs` | Per-external-plugin timeout | `120` |
| `allowed-hosts` | Whitelisted git hosts | `github.com gitlab.com bitbucket.org` |

### Outputs

| Output | Description |
|--------|-------------|
| `changed-entries` | JSON array of modified marketplace entry names |
| `changed-external` | JSON array of modified external plugin metadata |
| `changed-folders` | JSON array of modified in-repo folder paths |
| `result` | Overall validation status (`pass`/`fail`) |
| `report-path` | Filesystem path to generated markdown report |

## Practical Usage Example

A typical repository using this action would include:

```yaml

# .github/workflows/validate-plugins.yml

name: Validate Plugins

on:
  pull_request:
    paths:
      - '.claude-plugin/**'
      - '.github/actions/**'
  push:
    branches: [main]
    paths:
      - '.claude-plugin/**'
      - '.github/actions/**'
  workflow_dispatch:

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

      # Static pre-checks

      - run: ./.github/actions/validate-plugins/test-invariants.sh

      # Main validation

      - uses: ./.github/actions/validate-plugins
        id: validation
        with:
          marketplace-path: .claude-plugin/marketplace.json
          scope-errors-to-changed: "true"
          fail-on-warnings: "true"

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

```

When a contributor adds a new plugin folder under `.claude-plugin/plugins/my-new-plugin`, the action automatically:

1. Detects the folder change via Git diff
2. Enforces invariants (naming, ordering, SHA presence)
3. Validates the plugin manifest against the official Claude CLI schema
4. Blocks merge if any errors remain

## Key Source Files

| File | Purpose |
|------|---------|
| [`.github/workflows/validate-plugins.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/validate-plugins.yml) | Workflow orchestration |
| [`.github/actions/validate-plugins/action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/action.yml) | Composite action definition |
| [`.github/actions/validate-plugins/scripts/00-detect-changes.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/00-detect-changes.sh) | Git change detection |
| [`.github/actions/validate-plugins/scripts/11-validate-invariants.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/11-validate-invariants.sh) | Policy invariant implementation |
| [`.github/actions/validate-plugins/scripts/20-validate-cli-marketplace.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/20-validate-cli-marketplace.sh) | Marketplace CLI validation |
| [`.github/actions/validate-plugins/scripts/30-validate-cli-external.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/30-validate-cli-external.sh) | External plugin cloning and validation |
| [`.github/actions/validate-plugins/scripts/40-validate-cli-local.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/40-validate-cli-local.sh) | In-repo plugin validation |
| [`.github/actions/validate-plugins/scripts/90-report.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/90-report.sh) | Report generation and result synthesis |

## Summary

- The `validate-plugins` action is a **composite GitHub Action** that consolidates eleven distinct validation stages into a single reusable step
- It implements **selective validation** through Git-aware change detection, reducing CI time by testing only modified plugins
- **Custom invariants (I1–I11)** enforce community-specific policies beyond the base CLI schema
- **Resilient CLI installation** ensures the authoritative Claude validator is always available, even under adverse network conditions
- **Configurable severity** allows maintainers to tune invariant enforcement via `warn-invariants` and `fail-on-warnings` inputs
- **Security controls** include host whitelisting, SHA pinning requirements, and timeout-gated external cloning

## Frequently Asked Questions

### What triggers the validate-plugins workflow to run?

The workflow triggers on pull requests or pushes that modify files under `.claude-plugin/**` or `.github/actions/**`, plus any manual `workflow_dispatch` event. This path-filtering prevents unnecessary validation runs on unrelated changes.

### Why does the action use `fetch-depth: 0` during checkout?

Full Git history is required for accurate change detection in [`00-detect-changes.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/00-detect-changes.sh). Without complete history, the script cannot reliably determine which marketplace entries, external plugins, or local folders changed between the base ref and HEAD.

### Can I validate external plugins from hosts other than GitHub?

Yes, but you must update the `allowed-hosts` input. The default whitelist includes `github.com`, `gitlab.com`, and `bitbucket.org`. Adding custom hosts requires explicit configuration for security—arbitrary external repositories cannot be validated without approval.

### What happens if the Claude CLI installation fails?

The action implements retry logic with exponential backoff and post-install healing steps. If the `@anthropic-ai/claude-code` package installation encounters network issues, it automatically retries before failing the step, ensuring transient errors don't block legitimate plugin submissions.