.agents/skills/cut-release/SKILL.md
Publishing a release here is intentionally a one-action step: flip the existing Release Drafter draft from draft to published. Everything downstream is automated by GitHub Actions.
Meshery has no automatic release cadence - nothing publishes the draft on a schedule. The deliberate publish in this skill is the release.
.github/workflows/release-drafter.yml runs on every push to master (except
pushes touching only .github/**, which it ignores). As PRs merge it maintains a
single draft GitHub Release, titled Meshery v$NEXT_PATCH_VERSION with tag
v$NEXT_PATCH_VERSION (patch auto-increments). There is always exactly one draft
waiting to be published. Config: .github/release-drafter.yml.v* tag, which fires
.github/workflows/build-and-release-stable.yml (tag push). That single workflow
fans out to ctlrelease (mesheryctl via goreleaser), call-dde-release-workflow,
call-helm-chart-releaser, and email-meshery-release-notes-workflow as internal
jobs - those workflows are workflow_call/workflow_dispatch only and are not
separately triggered by the release event, so their absence from the run list is
expected, not a failure.released/published event also fires
.github/workflows/release-notes.yml (Release Notes Publisher) and Notify Remote
Providers.So the tag is already chosen and the notes are already drafted. Your job is only to make sure the merged PRs are reflected in the draft, then publish it. Do not create a tag, do not bump a version, do not write release notes by hand - Release Drafter owns all of that.
The draft only includes a PR after the drafter workflow run for that merge commit completes. If you publish too early, the just-merged PR is missing from the notes.
# Latest master commit that should be in the release
git fetch origin master --quiet && git rev-parse origin/master
# Most recent Release Drafter runs
gh run list --workflow=release-drafter.yml --branch master --limit 5 \
--json databaseId,status,conclusion,headSha,createdAt
The run whose headSha matches origin/master must be completed/success. If it
is still in_progress, wait (gh run watch <databaseId> --exit-status). If it
failed, stop and surface that - do not publish stale notes.
Caveat: because of the paths-ignore: '.github/**' filter, a master HEAD whose commit
touched only .github/** has no drafter run at all. Match against the newest
commit that did trigger one rather than concluding the drafter is broken.
gh api repos/meshery/meshery/releases \
--jq '.[] | select(.draft) | {id, tag: .tag_name, name, target: .target_commitish}'
gh api repos/meshery/meshery/releases/<id> --jq .body
Verify the PRs being released show up under a category heading. If they do not, the drafter run from step 1 has not indexed them - re-check step 1 rather than publishing without them.
Confirm the commit range too, not just the notes - a PR can be named in notes carried over from an earlier draft:
gh api repos/meshery/meshery/releases/latest --jq .tag_name # e.g. v1.0.64
git log <lastTag>..origin/master --oneline --grep='#<PR>'
If more than one draft is ever returned, stop and ask which to publish rather than guessing.
gh release edit <draftTag> --draft=false --latest
gh/gh-axi release edit --draft=false can report success and leave the release a
draft. Observed on 2026-08-07 cutting v1.0.65: edit: ok was printed and the
release was still "draft": true with a untagged-<hash> URL. Always re-read:
gh api repos/meshery/meshery/releases/<id> \
--jq '{tag: .tag_name, draft, published_at, html_url}'
draft: false and a non-null published_at are the only proof. If the flag silently
failed, publish through the REST API instead:
gh api -X PATCH repos/meshery/meshery/releases/<id> -F draft=false -f make_latest=true
Note -F draft=false (typed) - -f draft=false sends the string "false".
Then confirm the tag was created and points where you expect:
gh api repos/meshery/meshery/git/ref/tags/<draftTag> --jq '{ref, sha: .object.sha}'
A published release does not prove downstream ran. A release whose workflows never dispatched is not a cut release - report it if that happens.
gh api "repos/meshery/meshery/actions/runs?created=>$(date -u -v-5M +%Y-%m-%dT%H:%M:%SZ)" \
--jq '.workflow_runs[] | {name, event, status, url: .html_url}'
Expect at minimum Meshery Build and Releaser (stable) (event push, branch
v<version>) and Release Notes Publisher (event release). Report their run URLs.
release edit is not evidence of anything.