SuperAPI AI Directory

version-bump-reviewer

General & other

View repository

Updated 10-15 20:08

About this skill

Version Bump Reviewer

Decides whether a plugin or skill change needs a semver bump and at what tier, then propagates the new version through every file that has to stay in sync for this repo, and writes a conventional-commit message a future CHANGELOG generator can grep. This skill is the version-aware sibling to skill-review: skill-review flags policy and quality issues; this skill reasons about versioning and commits the result.

The primary question this skill answers is "does this change need a version bump, and if so, what tier?" — "no bump needed" is a first-class, expected outcome.

The skill is plugin-aware, not just SKILL.md-aware. Plugins can ship feature changes via many surfaces (a new .lsp.json, a new commands/foo.md, a new agent, a new MCP server, a new hook), and all of those should bump the owning plugin's version so installed users actually receive the update. Marketplace docs are explicit: users only get plugin updates when plugin.json.version (or the plugins[].version in marketplace.json) is bumped.

When to invoke

  • Auto-triggered by .claude/hooks/version-bump-reviewer.py whenever Edit, Write, or MultiEdit touches any of these paths:

    • plugins/<category>/<plugin>/skills/<name>/SKILL.md — plugin skill (existing).
    • .claude/skills/<name>/SKILL.md — repo-internal skill (existing).
    • plugins/<category>/<plugin>/commands/*.md — slash commands.
    • plugins/<category>/<plugin>/agents/*.md — subagents.
    • plugins/<category>/<plugin>/hooks/hooks.json — plugin hooks.
    • plugins/<category>/<plugin>/.lsp.json — LSP servers.
    • plugins/<category>/<plugin>/.mcp.json — MCP servers.
    • plugins/<category>/<plugin>/monitors/monitors.json — background monitors.
    • plugins/<category>/<plugin>/settings.json — default settings.
    • plugins/<category>/<plugin>/bin/** — shipped executables.
    • plugins/<category>/<plugin>/.claude-plugin/plugin.json — manifest (catches new plugin publishes and direct metadata edits).
    • .claude-plugin/marketplace.json — marketplace registry (catches new plugins[] entries and version drift).

    The hook runs alongside skill-edit-review.py; both fire independently. Address skill-review findings first, then run this skill.

  • Model-invoked when the user asks to bump a version, cut a release, prepare a skill for merge, introduce/publish a new plugin, verify whether a change needs a bump, or sync a plugin's package version.

  • Skip when no feature-bearing file is in the working tree (nothing drives a bump).

  • Skip when the diff is an empty touch with no real content change.

  • Skip when only non-behavior files changed (README.md, LICENSE, .gitignore, tests/**).

Change classes and version artifacts

The changed path(s) determine the change class and which version artifact(s) get bumped.

Path shape Class Version artifact(s)
plugins/<category>/<plugin>/skills/<name>/SKILL.md Plugin skill version in plugins/<category>/<plugin>/.claude-plugin/plugin.json and the matching plugins[] entry in .claude-plugin/marketplace.json, located by source == "./plugins/<category>/<plugin>". Bumped in lockstep, same tier.
plugins/<category>/<plugin>/<component> (commands, agents, hooks, .lsp.json, .mcp.json, monitors, settings, bin) Plugin component change Same artifacts as plugin skill — plugin.json + matching marketplace.json entry, in lockstep. SKILL.md is not touched.
.claude-plugin/marketplace.json adds a new plugins[] entry and the referenced plugin.json did not exist at HEAD New plugin publish Validate plugin.json.version == marketplace.json[].version; if mismatch, surface and pick the larger. No bump — this is initial publish. Emit feat commit.
.claude/skills/<name>/SKILL.md Repo-internal skill metadata.version in this SKILL.md's own frontmatter. Introduce the field at 0.1.0 if absent. No marketplace or plugin.json artifact applies.

The repo's top-level .claude-plugin/marketplace.json metadata.version is out of scope — it is informational only per Claude Code docs; per-plugin version is what gates user updates. Do not touch the top-level metadata.version.

Inputs the skill gathers

  1. The list of changed feature-bearing files in the working tree:

    $ git diff --name-only HEAD -- \
        'plugins/**/SKILL.md' \
        '.claude/skills/**/SKILL.md' \
        'plugins/**/commands/*.md' \
        'plugins/**/agents/*.md' \
        'plugins/**/hooks/hooks.json' \
        'plugins/**/.lsp.json' \
        'plugins/**/.mcp.json' \
        'plugins/**/monitors/monitors.json' \
        'plugins/**/settings.json' \
        'plugins/**/bin/**' \
        'plugins/**/.claude-plugin/plugin.json' \
        '.claude-plugin/marketplace.json'
    

    Plus git status --short to catch untracked new files.

  2. The full uncommitted diff for the chosen target path(s), via git diff HEAD -- <path> (or git diff --no-index /dev/null <path> for an untracked new file).

  3. The change class and, for plugin-skill or plugin-component changes, the owning plugin directory, its plugin.json version, and the matching marketplace.json plugins[].version.

  4. For a repo-internal skill, the current metadata.version in the SKILL.md frontmatter (or the fact that it is absent).

  5. The marketplace.json diff (only when that file changed), to detect new plugins[] entries that signal a new-plugin publish.

  6. A plugin-eval score for the SKILL.md before and after the change (see Phase 4) — only for SKILL.md targets, skipped for component-only and new-publish events.

Workflow

Phase 1 — Pick exactly one target

Run the changed-files query above. If empty, also check git status --short for untracked feature-bearing files.

Group the changed paths by owning plugin (or by SKILL.md for repo-internal skills, or by marketplace.json for the new-publish case):

  • A plugin-skill SKILL.md edit + a sibling component edit in the same plugin → one group, one bump, one commit. Rubric tier is the highest across both.
  • Two different plugins changed → two groups, handle alphabetically first by plugin path; list the rest for re-run.
  • A repo-internal skill change → its own group.
  • A marketplace.json change with a new plugins[] entry → its own group (new publish).

Outcomes:

  • Zero changed targets → tell the user there is nothing to review and stop.
  • One group → that is the target.
  • More than one group → pick the first one alphabetically by group key, do the full workflow for it, and at the end tell the user to re-run the skill for each remaining group (list them). Each group gets its own independent commit so the future CHANGELOG generator can attribute changes correctly.

Phase 2 — Resolve change class and version artifacts

Classify the target group:

  • Plugin skill — a SKILL.md matching plugins/<category>/<plugin>/skills/<name>/ is in the group. Owning plugin manifest: plugins/<category>/<plugin>/.claude-plugin/plugin.json. Marketplace entry: the element of .claude-plugin/marketplace.json plugins[] whose source is ./plugins/<category>/<plugin>.

    • Edge — unregistered plugin: if the plugin has a plugin.json but no matching marketplace.json entry, bump plugin.json only and surface a finding telling the user the plugin is not yet registered.
  • Plugin component change — the group has only feature-bearing component files (no SKILL.md), all under one plugin directory. Same artifacts as plugin skill (plugin.json + marketplace.json entry). SKILL.md is not edited.

  • New plugin publish — marketplace.json has a new plugins[] entry AND the referenced plugin directory's plugin.json did not exist at HEAD. Detect via:

    $ git show HEAD:plugins/<category>/<plugin>/.claude-plugin/plugin.json 2>/dev/null
    

    If the command fails (no such path at HEAD), this is a new publish. Artifacts: confirm parity between plugin.json.version and the new marketplace.json[].version. No bump. See Phase 2.5.

  • Repo-internal skill — .claude/skills/<name>/SKILL.md is in the group. The only artifact is metadata.version in the SKILL.md frontmatter.

Phase 2.5 — New-plugin publish short-circuit

If the change class is new plugin publish:

  1. Read plugin.json.version (call it MANIFEST_V) and the new marketplace.json[].version for the same source (call it MARKET_V).
  2. If MANIFEST_V != MARKET_V, surface this as a parity finding and take the larger as the published version. Edit the smaller artifact to match.
  3. If both match, no edits are needed for this phase.
  4. Skip Phases 3–6 entirely (no rubric, no bump computation).
  5. Continue to Phase 7 (no-op for parity-already-aligned), Phase 8 (validate), Phase 9 (commit as feat(<plugin>): introduce <plugin> at v<MANIFEST_V>).

Phase 3 — Read current versions and detect author intent

(Skip for new-plugin publish — already handled in Phase 2.5.)

  • Plugin skill or plugin component change: read plugin.json version (CURRENT_PLUGIN_VERSION) and the matching marketplace.json plugins[].version (CURRENT_MARKETPLACE_VERSION). They should match; if they don't, that's a finding to surface — proceed and bring both to the same new version.
  • Repo-internal skill: read metadata.version from the SKILL.md frontmatter (CURRENT_INTERNAL_VERSION). If the field is absent, this is a field-introduction case: treat the baseline as unset and default to 0.1.0 (see Phase 6).
  • Author intent / baseline. From git diff HEAD -- against the relevant manifest / frontmatter files, find any removed line (prefixed -) that set a version / metadata.version. If found, parse it as ORIGINAL_VERSION (the pre-edit baseline). If no version line was removed, set ORIGINAL_VERSION = CURRENT_*_VERSION. This anchors the author-bump floor in Phase 6.

Phase 4 — plugin-eval before/after signal (SKILL.md targets only)

This is a corroborating signal that feeds the tier decision for SKILL.md changes. It can escalate the rubric tier but must never silently lower it. The content-diff rubric (Phase 5) remains the primary classifier.

Skip entirely for plugin-component-only changes and for new-plugin publish. There is no SKILL.md diff to score; report plugin-eval: n/a (component change, no SKILL.md edit) in the commit body.

plugin-eval is pulled on demand via uvx — nothing is vendored. Use the same invocation contract as scripts/eval-skills.py:

$ SRC="${PLUGIN_EVAL_SOURCE:-git+https://github.com/wshobson/agents.git#subdirectory=plugins/plugin-eval}"
$ uvx --from "$SRC" plugin-eval score <dir> --depth quick --output json

--depth quick is the static layer only: deterministic, free, no API key — safe as a gate. standard/certify (LLM judge / Monte Carlo) are optional manual deep-dives; never require them for the bump decision.

  • BEFORE (skip if the SKILL.md is untracked / brand-new): create a temp dir, copy the skill directory into it, overwrite the copy's SKILL.md with the committed version, and score it:

    $ TMP=$(mktemp -d)
    $ cp -R <skill-dir>/. "$TMP"/
    $ git show HEAD:<path-to-SKILL.md> > "$TMP"/SKILL.md
    $ uvx --from "$SRC" plugin-eval score "$TMP" --depth quick --output json
    
  • AFTER: score the working-tree skill directory. Prefer scripts/eval-skills.py --skill <skill-dir> for parity with CI, or run the same uvx ... --output json command against <skill-dir> for an apples-to-apples JSON delta.

Capture composite.score and the summed anti_patterns count from each run. Compute Δscore and Δanti_patterns. Interpretation:

  • Δanti_patterns > 0 → a regression was introduced; the change is at least a semantic patch (fix) and the regression must be called out in the commit body.
  • Δscore materially negative → flag a quality regression to the user; do not silently proceed with a cosmetic classification.
  • Structural additions with Δscore ≥ 0 → corroborates a Minor classification.
  • Brand-new / untracked skill → no BEFORE; report the AFTER score as a sanity gate only and treat the change as an initial publish.

Phase 5 — Classify the diff

Apply the rubric below. Highest tier wins — if the diff touches Major and Minor categories, the result is Major. For SKILL.md targets, fold in the Phase 4 signal: the eval delta may push the result to a higher tier, never a lower one.

SKILL.md rubric (plugin skill or repo-internal skill)

Tier Triggers
Major A workflow step was removed; a tool was removed from allowed-tools or from the body's tool reference; the skill was renamed (frontmatter name changed); the skill's directory was relocated; required inputs/outputs changed in a way that breaks existing callers; a user-facing trigger was narrowed (e.g. description lost a context that previously activated the skill).
Minor A new workflow step was added; a tool was added; the description was broadened to cover new triggers; new optional functionality that doesn't break existing flows; new edge-case handling.
Patch (semantic) A small behavioral fix that changes how a step works without changing its inputs or outputs; correcting a wrong tool argument; tightening a regex or condition; any change where Δanti_patterns > 0.
Patch (cosmetic) Typos, prose clarifications, reordering paragraphs without semantic change, link fixes, formatting-only changes.

Plugin component rubric (commands, agents, hooks, .lsp.json, .mcp.json, monitors, settings, bin)

Tier Triggers
Major An existing command/agent file was deleted or renamed; a hook event matcher was removed; an .lsp.json language entry was removed; .lsp.json extensionToLanguage lost an extension; an .mcp.json server's command changed in a way that breaks callers; a monitor was removed; a settings key callers depended on was removed; a shipped binary was removed or its calling interface changed.
Minor A new command/agent/hook/lsp/mcp/monitor was added; extensionToLanguage gained a new extension; a new env var was introduced; a new args entry was added to an LSP server without changing existing behavior; a new shipped binary appeared.
Patch (semantic) Small behavioral fix — corrected a hook command's arguments, tightened a regex in a matcher, fixed a wrong transport, fixed a typo'd MCP server URL that nobody could have been depending on.
Patch (cosmetic) Prose-only edits inside a command/agent markdown body (the human-readable description text, not the frontmatter or instructions); whitespace-only JSON reformatting.

When the rubric is genuinely ambiguous, prefer the higher tier. A wrong Major bump is recoverable in the next release; a wrong Patch bump that should have been Major silently breaks downstream installs.

Phase 6 — Decide bump-or-not and compute the new version

(Skip for new-plugin publish — handled in Phase 2.5.)

No-bump outcome. A bump is not needed only when the change is a genuine no-op: an empty touch, a whitespace-only change, or a reordering that produces zero rendered difference — i.e. git diff HEAD -- <path> shows no semantic or visible content change. In that case report "no version bump is needed", explain why, and stop without editing or committing. This is the core "verify whether a bump is needed" answer and is a successful outcome.

A cosmetic content change (typo, prose clarification, link fix, formatting that changes rendered output) is not a no-op — it is a Patch (cosmetic) change and does bump (see Phase 5 and the conventional-commit table). Every committed behavior-bearing content change is attributable in the CHANGELOG; "no bump" never applies just because a change is small.

Otherwise compute the new version. Parse ORIGINAL_VERSION into MAJOR.MINOR.PATCH[-PRERELEASE] and apply the rubric (or escalated) tier:

  • Major → (MAJOR+1).0.0[-PRERELEASE]
  • Minor → MAJOR.(MINOR+1).0[-PRERELEASE]
  • Patch → MAJOR.MINOR.(PATCH+1)[-PRERELEASE]

The pre-release suffix (e.g. -alpha) is preserved verbatim. A pre-release stays pre-release until an author explicitly drops the suffix; this skill never makes that call.

Author-bump floor. If the diff changed a version (ORIGINAL_VERSION ≠ CURRENT_*), take the larger of (CURRENT_*, the rubric-computed version). Both are anchored to the same pre-edit baseline, so the comparison is meaningful: the author's intent is a floor, never a ceiling. If the rubric demands a higher tier, raise to it and explain why in the commit body. If no version change was in the diff, use the rubric-computed version directly.

Field-introduction (repo-internal, no metadata.version). If the SKILL.md had no metadata.version, introduce it at 0.1.0 (or 0.1.0-alpha if the author clearly intends pre-release). The conventional commit type is feat (initial versioning).

Brand-new SKILL.md. If the file is untracked, do not bump — accept whatever version the author wrote (default 0.1.0); the conventional commit type is feat.

Phase 7 — Apply the version edit(s)

  • Plugin skill or plugin component change: use Edit to change version in plugins/<category>/<plugin>/.claude-plugin/plugin.json, and the matching plugins[].version in .claude-plugin/marketplace.json, both to the new version. Match enough surrounding context (the plugin's name/source) to be unambiguous. If the plugin is unregistered in marketplace.json, edit only plugin.json and keep the unregistered-plugin finding for the report. For component-only changes, do not edit the SKILL.md — it didn't change.
  • Repo-internal skill: use Edit to change (or introduce) metadata.version in the SKILL.md frontmatter. If introducing, add a metadata: block with version: under the frontmatter, matching the existing YAML style.
  • New plugin publish: if parity was already aligned in Phase 2.5, no edits in this phase. If parity was off, the edit was already made in Phase 2.5.

Phase 8 — Validate

  • If plugin.json and/or marketplace.json were edited (plugin skill, plugin component change, or new publish with parity fix), run:

    $ make verify-structure
    

    This validates the marketplace structure and plugin manifests before the commit lands.

  • The Phase 4 AFTER score (when run) already exercised plugin-eval. Require that Δanti_patterns <= 0 relative to BEFORE (no new anti-patterns introduced by the version edits). For a repo-internal skill with no manifests touched, make verify-structure is not required. For component-only and new-publish changes, plugin-eval is n/a and there is no anti-pattern check.

If validation fails, abort before committing — leave the file edits on disk, surface the tool output to the user, and tell them to fix the underlying issue and re-run. Don't roll back the version edits; the user may want to see them.

Phase 9 — Stage and commit

Stage exactly the files this skill touched:

  • Plugin skill: git add <path-to-SKILL.md> <plugin.json> .claude-plugin/marketplace.json (omit marketplace.json if the plugin is unregistered).
  • Plugin component change: git add <component-paths...> <plugin.json> .claude-plugin/marketplace.json. The component files are the user's already-staged or unstaged work; pull them in alongside the version bump so the commit is self-contained.
  • New plugin publish: git add <plugin-root>/ .claude-plugin/marketplace.json — the whole new plugin directory plus the marketplace entry.
  • Repo-internal skill: git add <path-to-SKILL.md>.

Then commit using the format below. Pass the message via heredoc so multi-line bodies work:

$ git commit -m "$(cat <<'EOF'
<type>(<scope>): <subject> (v<NEW_VERSION>)

- <bullet 1: what changed>
- <bullet 2: plugin/marketplace version bumped to <NEW_VERSION>, or "initial publish">
- <bullet 3: plugin-eval delta — Δscore / Δanti_patterns, or "n/a (component change)">
- <bullet 4: only if author already bumped — note we raised it to match the rubric>

[BREAKING CHANGE: <description>]   # only present when type is feat!
EOF
)"

Confirm the commit landed with git status and git log -1 --oneline. Don't push.

Conventional commit format

The skill produces commits in this exact shape so a future CHANGELOG generator can git log --grep '(v[0-9]' and parse them deterministically.

Bump tier Commit type Scope Notes
Major (SKILL.md) feat(<skill-name>)!: skill directory Add BREAKING CHANGE: footer
Minor (SKILL.md) feat(<skill-name>): skill directory
Patch (semantic, SKILL.md) fix(<skill-name>): skill directory
Patch (cosmetic, SKILL.md) chore(<skill-name>): skill directory Typos, prose, link fixes
Major (plugin component) feat(<plugin-name>)!: plugin name Add BREAKING CHANGE: footer
Minor (plugin component) feat(<plugin-name>): plugin name e.g. "add .lsp.json"
Patch (semantic, component) fix(<plugin-name>): plugin name
Patch (cosmetic, component) chore(<plugin-name>): plugin name
New plugin publish feat(<plugin-name>): plugin name "introduce at v<X.Y.Z>"
New skill / first version feat(<skill-name>): skill directory "introduce at v<X.Y.Z>"

Scope rule: when the change is driven by a SKILL.md edit, scope is the skill directory name (twitter-to-reel, doc-generator). When the change is a plugin component change or a new plugin publish (no SKILL.md driving it), scope is the plugin name (basedpyright-lsp, agent-harness). For a mixed group where both a SKILL.md and a component changed in the same plugin, use the skill name as the scope and mention the component changes in the body.

The subject line must end with (v<NEW_VERSION>) — that trailing tag is the grep anchor for the CHANGELOG generator. For a plugin skill or plugin component change the anchor is the new plugin version; for a repo-internal skill it is the new metadata.version; for a new publish it is the initial version.

Examples

Minor — added a tool to a plugin skill (twitter-tools plugin at v0.1.0):

feat(twitter-to-reel): add caption-overlay step (v0.2.0)

- Insert Step 4.5 to burn a caption overlay before export
- twitter-tools plugin bumped to v0.2.0 (plugin.json + marketplace.json)
- plugin-eval: Δscore +0.02, Δanti_patterns 0

Patch (cosmetic) — prose/typo fix in a plugin skill (twitter-tools plugin at v0.1.0):

chore(twitter-to-reel): clarify --debug troubleshooting wording (v0.1.1)

- Reword the Debug mode bullet for clarity (no behavior change)
- twitter-tools plugin bumped to v0.1.1 (plugin.json + marketplace.json)
- plugin-eval: Δscore 0, Δanti_patterns 0

Field-introduction — repo-internal skill with no prior metadata.version (doc-generator); always feat at v0.1.0 regardless of the diff's tier:

feat(doc-generator): introduce versioning at v0.1.0 (v0.1.0)

- Add metadata.version: 0.1.0 to frontmatter (field did not exist)
- plugin-eval: Δscore 0, Δanti_patterns 0

Major — removed a step and changed required inputs (plugin skill at v1.0.1):

feat(twitter-media-downloader)!: drop legacy single-url path (v2.0.0)

- Remove Step 0a (single-url fallback) — batch input is now required
- twitter-tools plugin bumped to v2.0.0 (plugin.json + marketplace.json)
- plugin-eval: Δscore -0.01, Δanti_patterns 0

BREAKING CHANGE: callers passing one URL via the legacy path must now pass an
array under `urls`. The single-url path was deprecated in v1.0.0.

Author-bumped floor — author wrote 0.1.1 for a typo, but the diff also adds a step:

feat(doc-generator): add type-stub extraction step (v0.2.0)

- Add Step 3.5 to extract type stubs before rendering
- plugin-eval: Δscore +0.03, Δanti_patterns 0
- Author bumped metadata.version to 0.1.1; raised to 0.2.0 because a new
  workflow step is a minor change

New plugin publish — a new plugins[] entry for basedpyright-lsp (no prior history):

feat(basedpyright-lsp): introduce basedpyright-lsp at v0.1.0 (v0.1.0)

- Register basedpyright-lsp plugin in .claude-plugin/marketplace.json
- Initial publish at v0.1.0 (plugin.json + marketplace.json parity verified)
- plugin-eval: n/a (no SKILL.md in this plugin)

Plugin component minor — added a new slash command to an existing plugin (agent-harness plugin at v0.2.0, no SKILL.md change):

feat(agent-harness): add /status command (v0.3.0)

- Add commands/status.md exposing /agent-harness:status to inspect agent state
- agent-harness plugin bumped to v0.3.0 (plugin.json + marketplace.json)
- plugin-eval: n/a (component change, no SKILL.md edit)

Plugin component patch (semantic) — fixed a wrong matcher in a plugin hook (agent-harness plugin at v0.3.0):

fix(agent-harness): tighten PreToolUse matcher to avoid false positives (v0.3.1)

- Replace `Edit|Write` matcher with `Edit|Write|MultiEdit` in hooks/hooks.json
- agent-harness plugin bumped to v0.3.1 (plugin.json + marketplace.json)
- plugin-eval: n/a (component change, no SKILL.md edit)

Plugin component major — removed an LSP language entry (plugin at v1.0.0):

feat(basedpyright-lsp)!: drop .pyw support from extensionToLanguage (v2.0.0)

- Remove ".pyw" from .lsp.json extensionToLanguage
- basedpyright-lsp plugin bumped to v2.0.0 (plugin.json + marketplace.json)
- plugin-eval: n/a (component change, no SKILL.md edit)

BREAKING CHANGE: .pyw files are no longer routed to basedpyright-langserver
via this plugin. Users who depended on .pyw routing must add their own
extension mapping or install a separate plugin.

Edge cases

  • No version artifact found for a plugin skill / component change. If neither plugin.json nor a marketplace.json entry exists for the owning plugin, surface this as a structural problem and stop — don't fabricate a manifest.
  • plugin.json and marketplace.json versions disagree. Treat the larger as the floor; bring both to the same new version and note the prior drift in the commit body.
  • Repo-internal skill without metadata.version. Introduce it at 0.1.0; commit type feat; subject "introduce versioning at v0.1.0".
  • Author manually edited plugin.json/marketplace.json already. Their bump is the floor; use the larger of (author's version, rubric-computed version).
  • Multiple change groups in one working tree. Handle the alphabetically first one, tell the user to re-run for the rest, and list the remaining group keys.
  • The diff is an empty touch. Report "no bump needed" and stop.
  • Component change with no version artifact. If a component file changed inside plugins/<category>/<plugin>/ but the plugin has no plugin.json (structural bug), surface and stop.
  • Mixed SKILL.md + component change in the same plugin. Treat as a single plugin bump — highest tier wins across both diffs. Commit scope is the skill name; the body lists both the SKILL.md change and the component change.
  • Marketplace.json diff adds an entry but the plugin directory doesn't exist on disk. Bad merge or stale registration. Surface and stop — do not commit a marketplace entry pointing at nothing.
  • New plugin publish with mismatched plugin.json and marketplace.json versions. Pick the larger as the published version, edit the smaller to match, and note the parity fix in the commit body.
  • skill-review reported critical or high findings. Don't commit. Tell the user to resolve the findings first; this skill is the last step before commit, not the first.
  • Pre-release with no numeric component to bump (e.g. 1.0.0-rc.5). Bump the numeric part as usual (1.0.1-rc.5); don't increment the rc counter — that's an author call.
  • plugin-eval invocation fails (network/upstream churn). Report the failure, fall back to the content-diff rubric alone for the tier decision, and note in the commit body that the eval signal was unavailable. Pin a known-good revision via PLUGIN_EVAL_SOURCE if upstream is flaky. (Only applies to SKILL.md targets; component-only changes already skip eval.)

What this skill is NOT

  • Not a code or policy reviewer. skill-review does that and runs in its own hook.
  • Not a structural validator. make verify-structure does that; this skill calls it but doesn't reimplement it.
  • Not a quality scorer. plugin-eval does that; this skill consumes its score as a signal but does not reimplement scoring.
  • Not a CHANGELOG generator. That's a separate, future skill that consumes the commits this skill produces.
  • Not a release publisher. Doesn't push, doesn't tag, doesn't open PRs.
  • Not an owner of the top-level marketplace.json metadata.version. That umbrella package version is informational only and is not driven by individual plugin or skill changes.