AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Release

skill-cboone-agent-harness-plugins-release · by cboone

>-

No reviews yet
0 installs
41 views
0.0% view→install

Install

$ agentstack add skill-cboone-agent-harness-plugins-release

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-cboone-agent-harness-plugins-release)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Release? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Release

Prepare a versioned release or Claude Code marketplace catalog state tag: analyze commits, update release files, create a release commit, tag locally, and optionally publish a GitHub Release.

Options

The user may provide these options inline:

  • --major: Force a major version bump regardless of commit analysis
  • --minor: Force a minor version bump regardless of commit analysis
  • --patch: Force a patch version bump regardless of commit analysis
  • --dry-run: Preview all changes without modifying any files, committing, or tagging

Workflow

1. Pre-Flight Checks

Run these commands in parallel to understand the current state:

# Check for uncommitted changes
git status --porcelain

# Get current branch name
git branch --show-current

# List existing version tags, sorted by version
git tag --list 'v*' --sort=-version:refname

# List existing Claude Code marketplace catalog state tags
git tag --list 'catalog-M*-m*-p*-n*' --sort=-creatordate

# Get today's date
date +%Y-%m-%d

# Check for a release workflow that publishes GitHub Releases automatically
if [ -d .github/workflows ]; then
  for f in .github/workflows/*.yml .github/workflows/*.yaml; do
    [ -f "$f" ] || continue
    # Tag-triggered workflows: a `tags:` trigger plus a list entry like
    # `- "v*"` or `- catalog-*`.
    has_tag_trigger=0
    if grep -q 'tags:' "$f" && grep -qE "^[[:space:]]*-[[:space:]]+['\"]?(v[*[0-9]|catalog-)" "$f"; then
      has_tag_trigger=1
    fi
    # Marketplace push-to-main automation: workflow invokes the canonical
    # catalog state computation, publishes a GitHub Release, AND triggers
    # on push to the default branch (main or master). All three are
    # required. The compute-catalog-state and gh release create checks
    # rule out partial automation (e.g., a validation workflow that
    # computes the catalog state without tagging or releasing). The push
    # trigger check rules out workflow_dispatch-only or PR-only workflows
    # that happen to mention both strings: those will not run when a
    # commit lands on main, so deferring to them would silently skip
    # local catalog tagging and leave nothing tagged or released. The
    # branches:/main match must occur *under* push: rather than under a
    # sibling key like pull_request: -- otherwise a workflow with
    # `pull_request: branches: [main]` would falsely match. The awk
    # script tracks indentation to scope branches: matches to the push:
    # block, and handles both inline (`branches: [main]`) and YAML-list
    # (`branches:` followed by `- main`) forms.
    has_marketplace_push_to_main=0
    if grep -q 'compute-catalog-state' "$f" && grep -q 'gh release create' "$f" && awk '
        function leading_ws(s) {
          match(s, /^[[:space:]]*/)
          return RLENGTH
        }
        {
          # When indentation falls back to the push: level (or shallower),
          # we have left the push: block. Reset state before running other
          # rules on this line so a sibling key (e.g. pull_request:) does
          # not pick up branches: matches inside push:.
          if (in_push && $0 !~ /^[[:space:]]*$/ && leading_ws($0) \t`. Preserve the workflow kind, because marketplace catalog releases handle the two kinds differently. If a workflow matches both kinds, the loop reports `marketplace-push-to-main`, which is the more specific automation and the only writer of marketplace catalog tags:

- **Tag-triggered workflows**: a `tags:` trigger plus a YAML list entry whose value starts with `v` followed by `*`, `[`, or a digit (e.g., `- "v*"`, `- "v[0-9]+.[0-9]+.[0-9]+"`), or starts with `catalog-`. Anchoring to list-item form avoids false positives from action refs like `actions/checkout@v4`.
- **Marketplace push-to-main workflows**: a workflow that invokes `bin/compute-catalog-state`, runs `gh release create`, and triggers on push to the default branch (`main` or `master`). All three signals together mark end-to-end automation that tags and publishes on push to the default branch. A workflow that only computes the catalog state (e.g., for validation) does not qualify, and neither does a workflow_dispatch-only or PR-triggered workflow that happens to invoke both, since neither will run when a commit lands on main.

Detection is best-effort and may miss inline list forms (e.g., `tags: ['v*']`) or other exotic patterns. If the detection seems wrong, ask the user to confirm. This workflow kind affects M4-M8 for marketplace releases and step 11 for SemVer releases. For marketplace releases, only a **marketplace push-to-main workflow** skips local catalog tagging; a **tag-triggered workflow** still needs M7 to create the exact `catalog-*` tag so pushing that tag can fire the workflow.

**Abort conditions:**

- If the working tree is dirty (uncommitted changes exist), tell the user to commit first (suggest `/commit`) and stop.
- If this is not a git repository, report the error and stop.

### 2. Detect Project Type

Use the detection rules in `./references/project-types.md` to determine the project type. Check in priority order:

1. Claude Code marketplace (`.claude-plugin/marketplace.json` exists and has a top-level `plugins` array)
1. Go CLI (`go.mod` + `cmd/` or `.goreleaser.yml`/`.goreleaser.yaml`)
1. Go library (`go.mod` without main-package indicators)
1. Generic (fallback)

Report the detected type to the user. If the detection is ambiguous (e.g., multiple indicators conflict), ask the user to confirm.

If the project is a Claude Code marketplace, use the marketplace release flow below instead of the SemVer flow in steps 3-11.

### Claude Code Marketplace Release Flow

Claude Code marketplace repos use SemVer for individual plugin `version` fields, but the marketplace `metadata.version` is a catalog state tag, not SemVer.

The catalog state tag format is:

```text
catalog-M-m-p-n

Compute it from .claude-plugin/marketplace.json .plugins[].version exactly:

  • M: sum of all plugin major versions.
  • m: sum of all plugin minor versions.
  • p: sum of all plugin patch versions.
  • n: number of marketplace plugins.
  • Do not normalize or carry between components.
M1. Find Last Marketplace Release

Find the most recent marketplace catalog tag:

git tag --list 'catalog-M*-m*-p*-n*' --sort=-creatordate | head -1

If no catalog tags exist, this is the first marketplace release.

M2. Analyze Commits and Plugin Versions

Analyze commits since the last catalog tag, or all commits if no catalog tag exists:

git log ..HEAD --format='%H %s' --no-merges

For the first marketplace release:

git log --format='%H %s' --no-merges

Use the conventional commit analysis from step 4 to summarize changes. Identify which plugin directories changed and ensure each changed plugin gets an appropriate SemVer bump in both plugins//.claude-plugin/plugin.json and the matching marketplace entry. If those plugin version bumps are already present, preserve them.

Abort condition: If there are no commits since the last catalog tag, report that there is nothing to release and stop.

Confirm the individual plugin version changes with the user before modifying files. If --dry-run was specified, do not modify files; report the plugin version changes that would be made, the catalog state that would result, and stop after the dry-run pre-tag review in M5.

M3. Compute Catalog State

After plugin versions are final, compute the catalog state from marketplace plugin versions. Prefer the project's helper script when present so the skill stays in sync with whatever the repository considers canonical:

if [ -f bin/compute-catalog-state ]; then
  if [ -x bin/compute-catalog-state ]; then
    bin/compute-catalog-state
  else
    # Helper exists but lost its executable bit. Fail loudly rather than
    # falling back to the inline jq: the helper is the single source of
    # truth that bin/validate-plugins and the release workflow consume,
    # and silently bypassing it would let /release publish a tag the
    # validator and CI then reject.
    echo "bin/compute-catalog-state exists but is not executable. Run 'chmod +x bin/compute-catalog-state' (and commit the mode bit) before re-running /release." >&2
    exit 1
  fi
else
  jq -r '
    def parse_version:
      capture("^(?[0-9]+)\\.(?[0-9]+)\\.(?[0-9]+)$")
      | {
          major: (.major | tonumber),
          minor: (.minor | tonumber),
          patch: (.patch | tonumber)
        };

    [.plugins[].version | parse_version] as $versions
    | "catalog-M\($versions | map(.major) | add)-m\($versions | map(.minor) | add)-p\($versions | map(.patch) | add)-n\($versions | length)"
  ' .claude-plugin/marketplace.json
fi

The inline fallback applies only when the helper is absent (e.g., older repos that have not adopted bin/compute-catalog-state). It uses strict MAJOR.MINOR.PATCH parsing (matching bin/validate-plugins) so malformed versions fail loudly instead of silently producing an incorrect tag.

Update .claude-plugin/marketplace.json metadata.version to exactly the computed catalog state.

M4. Reconcile Existing Catalog State Tag

Before any commit or tag operation, check whether the exact catalog state tag already exists, locally and (if a remote is configured) on the remote, and reconcile against HEAD.

Compare commit SHAs, not just the tag name. The catalog-state format is sum-based and not collision-free: two different plugin-version mixes can produce the same component sums (for example, +1 minor on plugin A paired with -1 minor on plugin B). Treating any same-named tag as "already released" would silently drop a real catalog change. Comparing SHAs lets the skill idempotently skip true repeats while loudly aborting on real collisions.

A same-named tag at a different commit does not always mean a collision, though. The release workflow legitimately reuses an existing catalog tag when later commits leave every plugin's version unchanged (for example, a docs-only follow-up after a marketplace bump). M4 must mirror that logic so /release does not falsely report a collision and tell the user to bump versions when there is genuinely nothing to release.

head_commit="$(git rev-parse HEAD)"

# Annotated tags expose the commit they point to via the peeled refspec
# (^{}). Lightweight tags expose the commit directly. Try both locally.
local_commit="$(git rev-parse -q --verify "refs/tags/CATALOG-STATE^{commit}" 2> /dev/null || true)"

# Only consult the remote when one is configured. Repos without an
# `origin` remote (preparing a release locally and publishing later) must
# not fail here just because `git ls-remote origin` would error out.
remote_commit=""
if git remote get-url origin > /dev/null 2>&1; then
  # Capture ls-remote's output and exit status separately. Piping straight
  # into `cut` would mask auth/network failures: cut succeeds on empty
  # input, so an authentication error or a transient network failure
  # would leave remote_commit empty and silently fall back to the local
  # tag. That can mask an already-published remote CATALOG-STATE tag and
  # surface the conflict only when the eventual `git push` fails.
  if ! ls_remote_output="$(git ls-remote origin "refs/tags/CATALOG-STATE^{}" "refs/tags/CATALOG-STATE" 2>&1)"; then
    {
      echo "git ls-remote origin failed:"
      printf '%s\n' "${ls_remote_output}"
      echo
      echo "Cannot verify whether catalog state CATALOG-STATE is already published on origin."
      echo "Resolve the network or authentication issue and re-run /release rather than"
      echo "proceeding with a possibly-stale local view of remote tags."
    } >&2
    exit 1
  fi
  # Prefer the peeled refspec (annotated tags); fall back to the unpeeled
  # refspec (lightweight tags). Both are queried in one ls-remote call.
  remote_commit="$(printf '%s\n' "${ls_remote_output}" | awk '$2 == "refs/tags/CATALOG-STATE^{}" {print $1; exit}')"
  if [[ -z "${remote_commit}" ]]; then
    remote_commit="$(printf '%s\n' "${ls_remote_output}" | awk '$2 == "refs/tags/CATALOG-STATE" {print $1; exit}')"
  fi
fi

# Prefer the remote tag whenever it exists. Published tags are
# authoritative; a stale or recreated local tag pointing at HEAD must
# not mask a remote ref pointing at a different commit. Track whether
# the matching tag came from the remote or only from the local clone:
# a local-only tag is not proof that the catalog state was published.
existing_commit=""
existing_tag_source=""
if [[ -n "${remote_commit}" ]]; then
  existing_commit="${remote_commit}"
  existing_tag_source="remote"
elif [[ -n "${local_commit}" ]]; then
  existing_commit="${local_commit}"
  existing_tag_source="local"
fi

Cases:

  • No existing tag (existing_commit empty): proceed.
  • Remote tag exists at HEAD (existing_tag_source=remote): do not retag. If no release workflow was detected, continue to M8c so the skill can verify or create the GitHub Release for the existing remote tag; a previous manual release may have pushed the tag and failed before gh release create. If a release workflow was detected, report that the catalog tag is already on the remote and the workflow owns GitHub Release publication; do not push the tag again.
  • Only a local tag exists at HEAD (existing_tag_source=local): the catalog state is already tagged locally, but it is not known to be published. Do not report that there is nothing to release. Continue to M5-M8, skip creating a replacement tag in M7, and publish the existing local tag if the user chooses to publish. If no remote is configured, M8 will stop with the normal "configure a Git remote" guidance.
  • Tag exists at a different commit: distinguish "catalog state genuinely unchanged" from "real collision" by comparing the marketplace plugin versions at the tagged commit against HEAD's. This is the same comparison .github/workflows/release.yml performs:

```bash taggedversions="$(git show "${existingcommit}:.claude-plugin/marketplace.json" 2> /dev/null | jq -ec '[.plugins[] | {name, version}]' || echo '')" head_versions="$(jq -ec '[.plugins[] | {name, version}]' .claude-plugin/marketplace.json)"

if [[ -n "${taggedversions}" && "${taggedversions}" == "${head_versions}" ]]; then # Plugin versions are identical, so the catalog state is unchanged. # Do not retag. If no release workflow was detected, continue to M8c # so the skill can create a missing GitHub Release for the existing # remote tag. Otherwise report that the release workflow owns publication. : else # Real catalog-state collision; abort with the message below. : fi ```

If tagged_versions is empty (the tagged commit is not reachable locally, common when the branch lacks remote history), treat the situation as a collision rather than silently proceeding. The user can fetch the tag and re-run, or bump a plugin to break the apparent collision.

For the collision case, present this to the user:

Catalog state tag CATALOG-STATE already exists at a different commit
with different plugin versions.

Existing tag points to: 
Current commit:         

This is a catalog-state collision: the marketplace plugin versions
changed in a way that produces the same per-component sums as a
previously-released catalog state. The format is sum-based and not
collision-free.

To resolve, bump one plugin's version by an additional patch so the
marketplace produces a unique catalog state, then re-run /release.

Do not create another tag or choose a different state tag automatically. The user must change plugin versions to break the collision.

M5. Pre-Tag Review

Build a final review and wait for explicit user approval. The wording depends on which release workflow kind was detected in step 1.

If M4 found an existing catalog state tag to reuse and M3 produced no release-file changes, skip the pre-tag revi

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.