# How the bump-plugin-shas Workflow Detects and Updates Stale Plugin SHAs in the Claude Plugins Community

> Discover how the bump-plugin-shas workflow automatically detects and updates stale plugin SHAs in the Claude Plugins Community by comparing marketplace.json to live upstream references and opening pull requests.

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

---

**The bump-plugin-shas GitHub Workflow detects stale plugin SHAs by comparing pinned commits in [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/marketplace.json) against live upstream references, then validates and opens signed pull requests to update them.**

The `anthropics/claude-plugins-community` repository maintains a curated marketplace of external Claude plugins. To ensure security and stability, each plugin entry pins a specific Git commit SHA rather than floating on a branch. The bump-plugin-shas workflow automates the tedious work of detecting when upstream repositories advance and safely updating those pins.

## How the Workflow Discovers Stale SHA Pins

The core detection logic lives in [`.github/actions/bump-plugin-shas/scripts/bump.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/bump-plugin-shas/scripts/bump.sh). This script iterates over every external plugin entry in [`.claude-plugin/marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/marketplace.json) and performs a three-step staleness check.

### Resolving the Live Upstream Reference

For each marketplace entry, the script extracts:

- `source_url`: The Git repository URL
- `sha`: The currently pinned commit
- `subdirectory`: Optional path if the plugin lives in a sub-folder
- `tracking`: Optional config to track latest GitHub Release instead of HEAD

The script resolves the target reference using `git ls-remote`:

- **Default mode**: HEAD of the default branch
- **Releases-only mode**: The commit associated with the latest GitHub Release (fetched via API)

```bash

# Example: resolving HEAD for a GitHub repository

git ls-remote https://github.com/owner/repo.git HEAD

```

### The Staleness Comparison

An entry is flagged as **stale** when `new_sha != old_sha`. However, the script applies several granular safety checks before treating this as a genuine update candidate.

## Safety Checks and Guardrails

Before any SHA update proceeds, the workflow enforces multiple security layers defined in [`bump.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/bump.sh).

### Host Allow-List Enforcement

Only URLs whose host appears in the `ALLOWED_HOSTS` environment variable are processed. This prevents accidental processing of internal or untrusted repositories.

### Source-Owner Verification via GitHub API

The script queries the GitHub API to confirm the live repository still belongs to the same owner as the listed URL. This catches:

- Repository transfers to new owners
- Username changes that redirect to different accounts
- Typosquatting attempts through renamed repositories

### Identity Baseline Matching

When [`.github/owner-baseline.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/owner-baseline.json) exists, the script verifies the repository's account ID matches the recorded baseline. This detects cases where a login name has been reassigned to a completely different user or organization.

### Sub-Tree Suppression

For plugins in subdirectories, the script compares the actual tree objects:

```bash

# Compare subtree content between old and new commits

git rev-parse old_sha:subdirectory/
git rev-parse new_sha:subdirectory/

```

If the subdirectory bytes are identical, the bump is **suppressed as a no-op**—the parent repository moved but the plugin code did not change.

### Existing PR Guard

In `per-entry` mode, the script queries open PRs and skips plugins that already have a pending bump PR, preventing duplicate work.

## Freeze Lists and Exemption Config

The workflow respects intentional pinning through two mechanisms:

- **[`.github/freeze-shas.txt`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/freeze-shas.txt)**: Lists plugins whose SHAs are intentionally frozen, typically due to security concerns or known-breaking changes
- **SHA-exempt plugins**: Configured directly in the action inputs for plugins that should never auto-update

## Validation Before Commit

For each candidate that passes all checks, the workflow performs rigorous validation:

1. Clone the external repository at `new_sha`
2. Checkout the target commit
3. Run `claude plugin validate` against the plugin manifest
4. For `strict: false` plugins, synthesize a minimal manifest to enable validation

Only validated plugins proceed to the update phase.

## Creating Signed Commits and Pull Requests

The workflow uses GitHub's GraphQL API to create commits that satisfy the organization's `required_signatures` rule:

```graphql
mutation createCommitOnBranch {
  createCommitOnBranch(input: {
    branch: {id: $branchId},
    message: {headline: "bump(plugin): example-plugin to b7c8d9e"},
    fileChanges: {additions: [{path: ".claude-plugin/marketplace.json", contents: $encodedContent}]},
    expectedHeadOid: $currentOid
  }) {
    commit {oid}
  }
}

```

### Per-Entry vs. Batch Modes

| Mode | Branch Pattern | Use Case |
|------|---------------|----------|
| **per-entry** | `bump/<sanitized-plugin-name>` | Isolated review, granular rollback |
| **batch** | `bump` | Bulk updates, reduced noise |

Each mode creates appropriately scoped PRs with descriptive titles and summary tables.

## Post-PR Validation Dispatch

After opening bump PRs, the workflow automatically dispatches the [`validate-plugins.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/validate-plugins.yml) workflow on each branch. This satisfies the required "Validate Plugins" status check before human review.

## Running Locally for Debugging

You can execute the bump logic outside GitHub Actions for troubleshooting:

```bash

# Clone and enter the repository

git clone https://github.com/anthropics/claude-plugins-community.git
cd claude-plugins-community/.github/actions/bump-plugin-shas

# Configure environment

export MARKETPLACE_PATH=../../.claude-plugin/marketplace.json
export MAX_BUMPS=10
export ALLOWED_HOSTS="github.com"
export GH_TOKEN=$GITHUB_TOKEN
export PR_MODE=per-entry
export BASE_BRANCH=main

# Dry-run: preview what would change without making commits

MAX_BUMPS=0 ./scripts/bump.sh

```

## Manual Workflow Dispatch

Trigger the workflow with custom parameters via the GitHub CLI:

```bash
gh workflow run bump-plugin-shas.yml \
  --ref main \
  -f max_bumps=5 \
  -f plugin=my-plugin-name

```

This targets a single plugin or limits the batch size for controlled updates.

## Key Files in the bump-plugin-shas System

| File | Purpose |
|------|---------|
| [`.github/workflows/bump-plugin-shas.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/bump-plugin-shas.yml) | Orchestrates scheduled and manual runs |
| [`.github/actions/bump-plugin-shas/action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/bump-plugin-shas/action.yml) | Action interface and input definitions |
| [`.github/actions/bump-plugin-shas/scripts/bump.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/bump-plugin-shas/scripts/bump.sh) | Core detection, validation, and PR creation logic |
| [`.github/freeze-shas.txt`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/freeze-shas.txt) | Intentionally frozen plugin list |
| [`.github/owner-baseline.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/owner-baseline.json) | Optional owner identity verification data |
| [`.claude-plugin/marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/marketplace.json) | Source of truth for all plugin SHAs |
| [`.github/actions/validate-plugins/action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/action.yml) | Post-bump validation workflow |

## Summary

- The bump-plugin-shas workflow scans [`.claude-plugin/marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/marketplace.json) nightly to detect SHA pins that lag behind upstream repositories
- Staleness detection compares pinned commits against `git ls-remote HEAD` or latest GitHub Releases
- Multiple **safety checks**—host allow-list, owner verification, identity baseline, sub-tree comparison, and duplicate PR detection—filter out invalid or risky updates
- **Validation** via `claude plugin validate` ensures only working plugin code enters the marketplace
- **GraphQL-signed commits** satisfy organizational signature requirements
- **Per-entry and batch modes** offer flexibility between isolated review and operational efficiency

## Frequently Asked Questions

### How does the workflow prevent updating plugins from compromised repositories?

The workflow combines **source-owner verification** via GitHub API with optional **identity baseline matching** against [`.github/owner-baseline.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/owner-baseline.json). These checks ensure the repository still belongs to the expected account before accepting any new SHA, catching transfers or username reassignments that could indicate compromise.

### What happens if a plugin's upstream repository hasn't changed but its subdirectory has identical content?

The **sub-tree suppression** logic in [`bump.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/bump.sh) compares the actual tree object hashes of the subdirectory between old and new commits. If they match byte-for-byte, the update is suppressed as a no-op, avoiding unnecessary churn when only unrelated parent repository files changed.

### Can I prevent specific plugins from auto-updating?

Yes. Add plugin identifiers to [`.github/freeze-shas.txt`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/freeze-shas.txt) for repository-wide freezes, or configure **SHA-exempt plugins** in the action inputs for workflow-scoped exemptions. Both mechanisms are respected during the discovery phase before any staleness checks run.

### Why does the workflow use GraphQL instead of standard git commits for creating updates?

The `anthropics/claude-plugins-community` repository enforces `required_signatures` at the organization level, mandating GPG-signed commits. The GitHub GraphQL `createCommitOnBranch` mutation automatically signs commits with GitHub's web-flow GPG key, enabling automated commits that satisfy this policy without managing external signing keys in CI.