Claude Plugins validate-plugins GitHub Action: Validating Invariants I1-I11

The validate-plugins GitHub Action enforces all eleven marketplace invariants (I1-I11) in the anthropics/claude-plugins-community repository, including I2 (duplicate name detection) and I3 (minimum description length requirements), through automated bash scripts that parse marketplace.json and emit GitHub annotations.

The anthropics/claude-plugins-community repository maintains a curated plugin marketplace using a custom GitHub Action to ensure data integrity. The validate-plugins action serves as the automated gatekeeper for the marketplace.json file, verifying that every plugin entry adheres to strict structural and semantic standards defined by invariants I1 through I11.

I2 and I3: Core Invariants for Plugin Metadata

While the validate-plugins action verifies the complete suite of invariants I1-I11, invariants I2 and I3 specifically govern fundamental plugin identification and documentation standards. Note that historical documentation may reference these as II and III, which correspond directly to I2 and I3 in the current implementation.

I2 – No Duplicate Plugin Names

Invariant I2 ensures unique identification across the marketplace. The validation logic in .github/actions/validate-plugins/scripts/11-validate-invariants.sh scans the entire plugins array and fails if any two entries share identical name values.

According to the source code at lines 9-10 of 11-validate-invariants.sh, this check prevents CLI and UI addressing conflicts. When duplicate names are detected, the action emits a ::error annotation citing invariant I2. The test suite in .github/actions/validate-plugins/test-invariants.sh explicitly asserts this failure condition at line 56.

I3 – Minimum Description Length

Invariant I3 enforces documentation quality by requiring every plugin description to contain at least ten characters. This threshold is defined in .github/actions/validate-plugins/scripts/11-validate-invariants.sh at lines 28-30.

The validation fails with a ::error annotation when descriptions fall below this limit. The test-invariants.sh file contains a corresponding test case at line 61 that verifies the action correctly rejects descriptions shorter than ten characters.

How the Validation Pipeline Works

The validate-plugins action operates through a multi-stage pipeline defined in .github/actions/validate-plugins/action.yml and orchestrated by the workflow in .github/workflows/validate-plugins.yml.

Setup and Environment

The action initializes by copying the submitted marketplace.json into a temporary directory (VALIDATE_TMP). This isolation prevents mutation of source files during validation. The environment setup occurs in action.yml at lines 112-114, where the composite action prepares the validation workspace before executing the invariant checks.

Invariant Evaluation Logic

The core validation logic resides in scripts/11-validate-invariants.sh. This bash script iterates over the JSON array and applies each invariant check in sequence. The script parses marketplace metadata using jq and applies length comparisons and uniqueness validations to verify compliance with all eleven invariants.

Scoping and Error Severity

The action supports differential validation through the SCOPE_ERRORS_TO_CHANGED environment variable. When set to true, per-entry invariants (I3-I11) downgrade to warnings if the offending entry was not modified by the current PR. However, whole-marketplace invariants including I1, I2, and I7 never downgrade and always produce errors regardless of PR scope, as documented in the action's README.md.

GitHub Annotations

Validation results surface directly in pull request checks through GitHub's workflow command syntax. The action emits ::error and ::warning annotations that pinpoint exact line numbers and invariant violations for rapid developer feedback.

Code Examples

Valid Plugin Structure

The following marketplace.json entry passes both I2 and I3 validation:

{
  "plugins": [
    {
      "name": "awesome-plugin",
      "description": "A helpful plugin that does something useful.",
      "source": {
        "source": "url",
        "url": "https://github.com/example/awesome-plugin",
        "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
      }
    }
  ]
}

This structure contains a unique name (satisfying I2) and a description exceeding ten characters (satisfying I3).

I2 Violation: Duplicate Names

The following configuration triggers invariant I2:

{
  "plugins": [
    { "name": "dup-plugin", "description": "First instance.", "source": "./a" },
    { "name": "dup-plugin", "description": "Second instance.", "source": "./b" }
  ]
}

The action emits ::error file=marketplace.json::invariant I2: duplicate plugin names because both entries share the identifier dup-plugin.

I3 Violation: Short Description

This entry fails invariant I3:

{
  "plugins": [
    {
      "name": "short-desc",
      "description": "tiny",
      "source": "./x"
    }
  ]
}

The description tiny contains only four characters, falling below the ten-character minimum enforced by scripts/11-validate-invariants.sh lines 28-30.

Summary

  • The validate-plugins GitHub Action validates all eleven marketplace invariants (I1-I11) defined in the anthropics/claude-plugins-community repository.
  • I2 (No duplicate names) prevents CLI addressing conflicts by enforcing unique identifiers across the plugins array, as implemented at lines 9-10 of 11-validate-invariants.sh.
  • I3 (Description length) guarantees minimum documentation standards with a ten-character requirement defined at lines 28-30 of the same script.
  • The validation pipeline uses scripts/11-validate-invariants.sh for logic and test-invariants.sh for regression testing at lines 56 and 61.
  • Scoping rules allow per-entry invariants (I3-I11) to downgrade to warnings for unchanged entries, while whole-marketplace invariants (I1, I2, I7) always trigger errors.
  • Violations surface as GitHub annotations using ::error and ::warning workflow commands.

Frequently Asked Questions

What happens if a plugin fails invariant I2 or I3 during a pull request?

The validate-plugins action emits a GitHub ::error annotation that appears directly in the PR checks panel. For I2 (duplicate names) and other whole-marketplace invariants, this error always blocks merge regardless of which files the PR modified. The annotation includes the specific invariant identifier and the location in marketplace.json.

Can I bypass validation warnings for invariants I3-I11 if I'm not changing specific plugins?

Yes. When the SCOPE_ERRORS_TO_CHANGED environment variable is set to true, the action downgrades per-entry invariant violations (I3-I11) to warnings if the offending plugin entry was not modified by the current pull request. However, this scoping does not apply to I2, I1, or I7, which always produce blocking errors.

Where is the ten-character minimum for descriptions defined?

The description length requirement is implemented in .github/actions/validate-plugins/scripts/11-validate-invariants.sh at lines 28-30. This script contains the specific character count validation logic, while the corresponding test case in test-invariants.sh at line 61 verifies that descriptions shorter than ten characters trigger the appropriate error annotation.

How does the validate-plugins action handle the marketplace.json file?

The action.yml file defines a composite action that copies marketplace.json into a temporary directory (VALIDATE_TMP) during the setup phase at lines 112-114. The scripts/11-validate-invariants.sh script then parses this temporary copy using jq to evaluate all eleven invariants without risking modification of the original source file in the repository.

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 →