# What Is the `bump-plugin-shas` GitHub Action? A Deep Dive into Automated SHA Management for Claude Plugins

> Discover the bump-plugin-shas GitHub Action. It automates SHA updates for Claude plugins, validates code, and creates PRs, streamlining your development workflow.

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

---

**The `bump-plugin-shas` GitHub Action automatically updates pinned SHA commits for external Claude plugins in the marketplace manifest, validates the new code, and opens pull requests for maintainer review.**

This custom action in the `anthropics/claude-plugins-community` repository solves a critical maintenance problem: keeping third-party plugin references current without manual intervention. When upstream repositories move forward, this action detects changes, ensures plugin integrity through validation, and creates properly signed commits for security-conscious merging.

## How `bump-plugin-shas` Discovers Outdated Plugin SHAs

The action begins by scanning [`.claude-plugin/marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/marketplace.json) for every external plugin entry that contains a `source` object. These entries point to remote Git repositories that require SHA pinning for reproducible builds.

For each discovered plugin, the action determines the target reference:

- **Default tracking**: Compares against the repository's current `HEAD`
- **Releases-only tracking**: Checks the latest published GitHub release (configured via `tracking-config`)

This dual-mode approach lets maintainers choose stability (releases) or bleeding-edge updates (HEAD) on a per-plugin basis.

## Validation and Safety Guards in `bump-plugin-shas`

Before any SHA advances, the action enforces a multi-layer protection system:

### Validation Pipeline

When a newer commit exists, the action clones the repository, checks out the candidate SHA, and runs `claude plugin validate` against the plugin manifest. For plugins using `"strict": false`, it synthesizes a minimal manifest to ensure basic structural compliance. Failed validations abort the bump for that plugin—no broken code enters the manifest.

### Policy Enforcement Rules

| Guard | Purpose | Location |
|-------|---------|----------|
| **sha-exempt** | Lists plugins deliberately without SHA pins; completely ignored | Configurable list |
| **freeze-shas** | Plugins frozen at current SHA; logged warning, never bumped | [`.github/freeze-shas.txt`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/freeze-shas.txt) |
| **tracking-config** | JSON file specifying `"releases-only"` plugins | Repository config |
| **owner-baseline** | Verifies repository owner account ID matches recorded value | [`.github/owner-baseline.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/owner-baseline.json) |

The owner baseline check prevents a subtle attack vector: if a repository transfers ownership, the action detects the mismatch and stops automatic pinning to the new owner's code.

## PR Creation Modes: Batch vs. Per-Entry

The `pr-mode` input controls how changes reach maintainers:

**`batch`** mode creates a single signed commit on `bump/plugin-shas` (configurable) containing all successful bumps—efficient for routine maintenance with trusted plugins.

**`per-entry`** mode isolates each bump on its own branch (`bump/<sanitized-name>`) with individual PRs. This prevents one validation failure from blocking ten healthy updates. The repository's default workflow uses this safer approach.

Both modes use GitHub's GraphQL `createCommitOnBranch` mutation for **server-side signed commits**, satisfying the organization's `required_signatures` rule without exposing private keys to runners.

## Using `bump-plugin-shas` in Your Workflow

### Nightly Automated Run

```yaml

# .github/workflows/bump-plugin-shas.yml (excerpt)

- uses: ./.github/actions/bump-plugin-shas
  id: bump
  with:
    marketplace-path: .claude-plugin/marketplace.json
    max-bumps: ${{ inputs.max_bumps || '30' }}
    freeze-shas: ${{ steps.freeze.outputs.list }}
    only: ${{ inputs.plugin }}
    pr-mode: per-entry
    claude-cli-version: latest

```

The workflow triggers on cron schedule and manual dispatch, loading frozen pins before execution.

### Single-Plugin Manual Trigger

```yaml
workflow_dispatch:
  inputs:
    max_bumps:
      description: 'Cap on plugins bumped this run'
      default: '30'
    plugin:
      description: 'Bump ONLY this plugin name (empty = all stale)'
      default: ''

```

Supply a specific plugin name through the Actions UI for targeted updates—useful for urgent security patches or debugging.

## Core Implementation in [`bump.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/bump.sh)

The discovery and validation logic lives in [`scripts/bump.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/bump.sh):

```bash

# Simplified discovery loop from bump.sh lines 67-108

while IFS= read -r entry; do
  name=$(jq -r '.name' <<<"$entry")
  # Skip guards: sha-exempt, frozen, owner mismatch...

  
  new_sha=$(git ls-remote "$full_url" HEAD | awk '{print $1}')
  [[ "$new_sha" == "$old_sha" ]] && continue
  
  # Validate before accepting

  claude plugin validate "$manifest"
  
  # Record for commit/PR creation

  bumps+=("$name:$old_sha:$new_sha")
done < <(jq -c '.plugins[] | select(.source|type=="object")' "$MARKETPLACE_PATH")

```

This loop handles HEAD checks, release-only overrides, subtree suppression, validation gating, and finally delegates to the commit signing logic at lines 35-44.

## Action Outputs and Observability

After execution, `bump-plugin-shas` exposes structured data:

- `bumped`: JSON array of successful upgrades with `name`, `old_sha`, `new_sha`
- `skipped`: Array of rejected bumps with explanatory `reason`
- `pr-url` / `pr-urls`: Direct links to created pull request(s)

Downstream jobs can consume these outputs for notifications, metrics dashboards, or additional validation pipelines.

## Summary

- **`bump-plugin-shas`** automates SHA pin maintenance for external Claude plugins through discovery, validation, and policy-guarded PR creation
- **Two tracking modes** support both HEAD-following and release-only update strategies
- **Four safety guards** (sha-exempt, freeze-shas, tracking-config, owner-baseline) prevent unwanted or malicious updates
- **Server-side signed commits** via `createCommitOnBranch` maintain GPG verification without key exposure
- **Per-entry PR mode** isolates failures; **batch mode** optimizes for trusted plugins
- Primary implementation spans [`.github/actions/bump-plugin-shas/action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/bump-plugin-shas/action.yml) and [`scripts/bump.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/bump.sh)

## Frequently Asked Questions

### What triggers the `bump-plugin-shas` action to run?

The action runs on a scheduled cron (nightly by default) and via `workflow_dispatch` for manual execution. The triggering workflow at [`.github/workflows/bump-plugin-shas.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/bump-plugin-shas.yml) loads configuration, prepares the freeze list, then invokes the action with appropriate inputs.

### How does `bump-plugin-shas` handle plugin validation failures?

Validation failures skip the individual bump without aborting the entire run. The plugin name and failure reason populate the `skipped` output array. In `per-entry` PR mode, other plugins still receive their own PRs; in `batch` mode, the failing plugin is simply omitted from the collective commit.

### Why does the action use server-side commit signing instead of GPG keys on the runner?

The `createCommitOnBranch` GraphQL mutation generates commits with verified signatures directly through GitHub's API. This satisfies the `required_signatures` branch protection rule while eliminating the security risk of private signing keys in CI environments—no key material ever touches the action runner.

### Can I prevent `bump-plugin-shas` from updating specific plugins?

Yes. Add plugin names to [`.github/freeze-shas.txt`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/freeze-shas.txt) to freeze them at current SHAs, or to the `sha-exempt` list to ignore them entirely. For release stability, add plugins to the `"releases-only"` array in your tracking configuration file.