agentleFS
EndstoneMCEndstoneMC/endstone/.claude/skills/release/SKILL.md

release

Skill766 starsChanged 34 days agoApache-2.0View on GitHub

Cut a new Endstone release end-to-end - run prereq checks, curate CHANGELOG, stamp it, commit, tag, push, then watch the Build workflow publish. Use when the user asks to release/ship a new patch or minor version (e.g. "prepare release v0.11.4", "ship v0.12.0", "cut a release").

  • Reads credentials
  • Commits and pushes

196 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use create-agent-adapter, changelog-style and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • MicrosoftSkill

    create-agent-adapter

    Technical guide for creating a new Paperclip agent adapter. Use when building a new adapter package, adding support for a new AI coding tool (e.g. a new CLI agent, API-based agent, or custom process), or when modifying the adapter system. Covers the required interfaces, module structure, registration points, and conventions derived from the existing claude-local and codex-local adapters.

    Also in 5 projects that use this

  • GrinvSkill

    changelog-style

    Turn a commit range into CHANGELOG.md entries following common-changelog style. Use when finishing a PR or cutting a release, to write/fix the [Unreleased] section's entries — moving [Unreleased] under a new dated version heading is a separate, automated step (see the release skill / scripts/sync-version.ts), not this skill's job.

    Also in 4 projects that use this

  • GrinvSkill

    docs-consistency-check

    Check README/manifest.json/server.json/CHANGELOG.md/AGENTS.md and docs/*.md for drift against the actual registered tools and source. Use after adding, renaming, or removing a tool, or as part of a live-audit pass.

    Also in 4 projects that use this

  • Microsoft AzureSkill

    component-release

    Prepares a verifiable Agent Landing Zone UI release. Use for release branches, VERSION, changelog entries, tags, release notes, and compatibility evidence; never publish without explicit human approval.

    Also in 4 projects that use this

  • Microsoft AzureSkill

    documentation-consistency

    Keeps AI Landing Zone contributor, user, and operator documentation aligned with shipped Bicep behavior. Use for parameters, defaults, outputs, topology, deployment flow, operations, or releases.

    Also in 8 projects that use this

  • rivet-devSkill

    launch-graphics

    Generate agentOS marketing/launch graphics (launch & social heroes, code-snippet cards) from the committed generators in docs-internal/graphics. Use when asked to make, update, or render an agentOS launch image, social image, "agentOS Apps" graphic, or technical code-snippet image.

    Also in 3 projects that use this

  • +3 more from Grinv

The file

Show its rules and text

We split this skill into the rules it gives an agent

19 rules. 0 are common, 11 are distinctive, and 8 are very specific to this project.

  • 0

    Common

    Most of the 186 edited versions we read keep these.

  • 11

    Distinctive

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run these in parallel:

    line 56
  2. Very specific:

    Default = previous tag's patch + 1 (e.g.

    line 66
  3. Very specific:

    Verify all version-touching files match.

    line 69
  4. Distinctive:

    If any are stale, edit the constants directly.

    line 88
  5. Distinctive:

    If any update is needed and the user hasn't already confirmed the target version, STOP to confirm before editing.

    line 95
  6. Distinctive:

    If any check fails: surface the exact failure to the user and STOP.

    line 123
  7. Distinctive:

    Do not proceed with a dirty tree, an out-of-sync branch, or failing Build.

    line 124
  8. Very specific:

    Read CHANGELOG.md lines 1-30 to see what's already in [Unreleased].

    line 142
  9. Distinctive:

    Follow Keep a Changelog 1.1.0:

    line 152
  10. Very specific:

    If lowercase [unreleased]: ref-link duplicate exists, delete it.

    line 163
  11. Very specific:

    Do this with the Edit tool.

    line 173
  12. Very specific:

    Verify the section header ## [X.Y.Z] is unique and the section is non-empty - build.yml's release job greps for it on the runner and fails …

    line 210
  13. Distinctive:

    Run these sequentially (each depends on the previous):

    line 218
  14. Distinctive:

    If the push is rejected (someone else pushed first):

    line 230
  15. Distinctive:

    If git push succeeds but git push --follow-tags did not include the tag (rare.

    line 237
  16. Distinctive:

    Run in parallel after the Build run succeeds:

    line 291
  17. Very specific:

    If 0 N, push the release branch's tip to main directly (no local checkout switch needed):

    line 326
  18. Distinctive:

    Wrong commit got tagged: Avoid. If you must: delete the tag locally and on origin (git push --delete origin vX.Y.Z), yank from PyPI, delete …

    line 362
  19. Very specific:

    [Unreleased] must stay present after stamping: Don't rename it to [X.Y.Z] - copy contents into a new [X.Y.Z] stanza and leave …

    line 380

“Common” is measured: kept by at least 6 in 10 of the 186 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Release Endstone

This skill drives the release. Execute the steps in order. Each step has explicit commands; do not skip ahead. Stop and ask the user only at the points flagged "STOP".

Pipeline (what happens after the tag is pushed)

The repo splits its CI across three workflows:

  • ci.yml - Release builds on Linux + Windows, Debug+coverage on Linux. Runs on PR + push + dispatch. Does NOT trigger on tags.
  • docker.yml - Publishes ghcr.io/endstonemc/endstone:nightly from the from-source root Dockerfile. Develop branch only.
  • build.yml - Wheels matrix, bundle, docker image (short-path), PyPI publish, GitHub Release. The only workflow that fires on tag push - because ci.yml's triggers exclude tags and docker.yml is develop-only.
git push --follow-tags origin <branch>
                |
                v
        build.yml (DAG of jobs on tag push)
        +-----------------------------------+
        |   wheels    (cp311-15 x 2 OS)     |
        |       |                           |
        |       +-- bundle  (zip per OS)    |
        |       +-- docker  (GHCR/Hub push) |
        |       +-- release (PyPI + GH)     |
        +-----------------------------------+

release is a job inside build.yml that fires only on tag pushes; it needs wheels + bundle, publishes wheels to PyPI via OIDC, and creates the GitHub release with body extracted from CHANGELOG.md. docker builds the short-path image from the cp313 manylinux wheel artifact and pushes versioned + :latest to GHCR and Docker Hub.

Because the tag push is authored by the user (not GITHUB_TOKEN), build.yml actually triggers - that's why this skill does the tag push from the local checkout instead of from a workflow.

The package version comes from setuptools_scm (the tag IS the version). There is no version = ... field to edit.


Step 0 - figure out the target version

Run these in parallel:

git tag --sort=-version:refname | head -n5     # last 5 tags
git rev-parse --abbrev-ref HEAD                # current branch

The release branch must be v0.<minor> (currently v0.11); never release from main. Compute the next version:

  • Default = previous tag's patch + 1 (e.g. v0.11.3 -> 0.11.4).
  • For a minor/major bump (0.12.0, 1.0.0), the user must have said so.

Verify all version-touching files match. The bump-bds flow updates the BDS version constants in src/bedrock/shared_constants.h but typically misses other surfaces - check each one and edit it inline if it's stale.

grep -E 'project\(endstone VERSION' include/CMakeLists.txt
grep -E 'MajorVersion|MinorVersion|PatchVersion|NetworkProtocolVersion' src/bedrock/shared_constants.h
grep -E 'minecraft-v[0-9]+\.[0-9]+_\(Bedrock\)' README.md

Checklist:

  1. include/CMakeLists.txt project(endstone VERSION x.y.z ...) = the version being released. This is the fallback; the wheel build overrides ENDSTONE_VERSION with the exact setuptools_scm version, but the numeric major/minor/patch and ENDSTONE_API_VERSION come from here.
  2. src/bedrock/shared_constants.h SharedConstants must have:
    • MajorVersion/MinorVersion/PatchVersion = the supported BDS version
    • NetworkProtocolVersion = the BDS network protocol version If any are stale, edit the constants directly.
  3. README.md Minecraft badge (https://img.shields.io/badge/minecraft-vNN.NN_(Bedrock)-black) must match MinorVersion.PatchVersion from shared_constants.h. Update with Edit if stale - the badge URL is the only spot users see the supported BDS version on the project landing page.

If any update is needed and the user hasn't already confirmed the target version, STOP to confirm before editing.


Step 1 - pre-flight checks (all must pass)

Run in parallel:

git status --porcelain                                                                       # must be empty
git rev-list --left-right --count @{u}...HEAD                                                # must be "0 0"
gh run list --branch $(git rev-parse --abbrev-ref HEAD) --workflow=build.yml --limit 3
gh run list --branch $(git rev-parse --abbrev-ref HEAD) --workflow=ci.yml --limit 3

Pass conditions:

  1. Working tree clean. git status --porcelain returns nothing.
  2. In sync with origin. Left-right count is 0 0.
  3. Build green on HEAD. Latest Build run on this branch concludes success. Every wheel matrix job must pass - one failed manylinux_x86_64 or win_amd64 job means the release job's PyPI publish fails after the tag push, leaving an orphan tag.
  4. CI green on HEAD. Latest CI run (Release + Coverage) concludes success. Less critical than Build (CI doesn't gate the release path), but a red CI on the tag commit is a smell - investigate.

If any check fails: surface the exact failure to the user and STOP. Do not proceed with a dirty tree, an out-of-sync branch, or failing Build.

For a failed matrix job, fetch the log to diagnose:

gh api repos/EndstoneMC/endstone/actions/jobs/<job_id>/logs 2>&1 | tail -100

Step 2 - curate CHANGELOG [Unreleased]

List candidate user-visible commits:

git log --format='%h %s' v<prev>..HEAD

Read CHANGELOG.md lines 1-30 to see what's already in [Unreleased].

For each commit decide: user-visible?

  • Include: API additions/changes, behavioral changes, bug fixes plugin authors notice, supported-BDS version bumps, deprecations, security fixes.
  • Skip: refactors, internal class/struct changes, CI/build/toolchain changes (unless they force plugin devs to change something), comment edits, test-only changes, skill/doc-only changes.

Follow Keep a Changelog 1.1.0:

  • Group under ### Added / ### Changed / ### Deprecated / ### Removed / ### Fixed / ### Security. Omit empty groups.
  • Past tense, one bullet per change, written for plugin authors and server admins.
  • Prefix breaking changes with **BREAKING**: in the Changed/Removed group.
  • Python API references use snake_case and property syntax (Player.send_message, not Player::sendMessage).
  • Bedrock terminology: "block actor" not "block entity"; mark Java-only features as N/A.
  • If lowercase [unreleased]: ref-link duplicate exists, delete it.

Edit CHANGELOG.md to add anything missing. STOP and show the user the final [Unreleased] body before stamping - this is the one human approval point.


Step 3 - stamp CHANGELOG.md

Do this with the Edit tool.

Get the previous tag and today's date:

git tag --sort=-version:refname | head -n1     # PREV_TAG, e.g. v0.11.3
date -u +%Y-%m-%d                              # DATE, e.g. 2026-05-25

Make exactly two edits to CHANGELOG.md:

(a) Below the ## [Unreleased] header, insert a new version stanza, leaving [Unreleased] empty for the next cycle. Move every bullet that was under [Unreleased] into the new [X.Y.Z] block.

 ## [Unreleased]

-### Added
-- Added support for BDS version 1.26.20.
+## [X.Y.Z] - YYYY-MM-DD
+
+### Added
+- Added support for BDS version 1.26.20.

(b) In the reference-link block at the bottom of the file, update the [Unreleased] link to use the new tag as its base, and insert a new [X.Y.Z] compare link directly below it.

-[Unreleased]: https://github.com/EndstoneMC/endstone/compare/v<prev>...HEAD
+[Unreleased]: https://github.com/EndstoneMC/endstone/compare/vX.Y.Z...HEAD
+[X.Y.Z]: https://github.com/EndstoneMC/endstone/compare/v<prev>...vX.Y.Z
 [<prev>]: ...

Verify the section header ## [X.Y.Z] is unique and the section is non-empty - build.yml's release job greps for it on the runner and fails the publish if missing.


Step 4 - commit, tag, push

Run these sequentially (each depends on the previous):

git add CHANGELOG.md
git commit -m "Release X.Y.Z"
git tag -a vX.Y.Z -m "Release X.Y.Z"
git push --follow-tags origin $(git rev-parse --abbrev-ref HEAD)

--follow-tags pushes the commit and the annotated tag in one go. As soon as it returns, build.yml triggers on the tag push.

If the push is rejected (someone else pushed first):

git pull --rebase origin $(git rev-parse --abbrev-ref HEAD)
git push --follow-tags origin $(git rev-parse --abbrev-ref HEAD)

If git push succeeds but git push --follow-tags did not include the tag (rare; happens if the tag was pushed in a separate hook), explicitly git push origin vX.Y.Z.


Step 5 - watch the Build run

Tag pushes trigger only build.yml (ci.yml's push.branches filter excludes tags, docker.yml is develop-only). Confirm the Build run started:

gh run list --workflow=build.yml --limit 3

You should see a new Build run against vX.Y.Z (or the tag's commit SHA). If it's missing, the trigger didn't fire - investigate before declaring success.

Watch progress:

gh run watch <run_id>            # blocks until the run finishes
gh run view <run_id> --json jobs --jq '.jobs[] | {name, conclusion}'

For long-running watches, use run_in_background: true on the Bash tool with gh run watch <run_id> and check back later instead of polling.

Expected job outcomes on a tag push:

  • wheels (~15-20 min, parallel matrix): 10 wheels (cp311-cp315 × manylinux_x86_64/win_amd64). Linux wheels build inside the manylinux_2_31 container; deps come from the Linux-conan-Release-* cache populated by prior develop/main pushes. Artifacts uploaded with archive: false, so artifact names are the wheel filenames.
  • bundle (~1 min, needs wheels): produces endstone-X.Y.Z-windows-x86_64.zip and endstone-X.Y.Z-linux-x86_64.zip (cp313 wheel + start.cmd/start.sh + LICENSE + CHANGELOG).
  • docker (~5 min, needs wheels): builds the short-path image at .github/docker/Dockerfile from the cp313 manylinux wheel artifact, pushes ghcr.io/endstonemc/endstone:X.Y.Z,:latest and endstone/endstone:X.Y.Z,:latest.
  • release (~3 min, needs wheels + bundle, tag-only): publishes wheels to PyPI via OIDC, extracts the ## [X.Y.Z] CHANGELOG section, creates the GH release with body + uploaded bundle archives.

Total wall time ~25 min (bounded by wheels).


Step 6 - verify the artifacts

Run in parallel after the Build run succeeds:

gh release view vX.Y.Z                                                                              # release exists, has body, has bundle zips
pip index versions endstone                                                                         # PyPI lists X.Y.Z
gh api /orgs/EndstoneMC/packages/container/endstone/versions --jq '.[0].metadata.container.tags'    # GHCR has X.Y.Z
curl -s https://hub.docker.com/v2/repositories/endstone/endstone/tags?page_size=5 | jq '.results[].name'   # Docker Hub has X.Y.Z

Report the verified artifact list back to the user.


Step 7 - fast-forward main to the release commit

Convention in this repo: main tracks the latest release branch's HEAD, so downstream consumers of main get the release. The release branch is normally ahead of main; fast-forward main to it.

Safety check first:

git fetch origin main
git rev-list --left-right --count origin/main...origin/<release-branch>

Expected output: 0 N where N >= 1 (release branch is N commits ahead of main, main has no extra commits). Any other shape means a fast-forward is not safe:

  • M N with M > 0: main has its own commits not on the release branch -> STOP. A fast-forward would lose them. Ask the user how to reconcile (typically they want to cherry-pick or merge, not FF).
  • 0 0: already in sync, nothing to do.

If 0 N, push the release branch's tip to main directly (no local checkout switch needed):

git push origin origin/<release-branch>:main

This is a server-side fast-forward push - rejected by GitHub if it's not truly a FF, so it's safe to attempt. If you prefer a local merge:

git checkout main
git pull --ff-only
git merge --ff-only vX.Y.Z
git push origin main
git checkout <release-branch>

Release is done.


Recovery cookbook

  • release job failed (missing CHANGELOG section). Push a follow-up commit fixing the ## [X.Y.Z] header in CHANGELOG.md, then rerun the release job from the Actions UI.
  • One wheel matrix job failed. Rerun just that job from the Actions UI. Other jobs' artifacts are kept; the release job will pick them up on retry. Do NOT re-tag.
  • All wheels built but PyPI publish failed. Rerun the release job; wheels are already in artifacts.
  • docker job failed. Rerun from the Actions UI. The image build is independent of release, so PyPI publish proceeds regardless.
  • CHANGELOG typo, tag already pushed. Fix in a follow-up commit on the branch, then gh release edit vX.Y.Z --notes-file <new-body>.
  • Wrong commit got tagged. Avoid. If you must: delete the tag locally and on origin (git push --delete origin vX.Y.Z), yank from PyPI, delete the GH release, restart from Step 3.

Pitfalls

  • GITHUB_TOKEN pushes don't cascade. That's why this skill tags from the local checkout. Never reintroduce tag-creation inside a workflow without a PAT or GitHub App token.
  • Linux wheel needs autotools that actually work. Some Conan deps (libelf, openssl) shell out to autoreconf/m4. The cached m4/1.4.19 binary has been observed broken in our manylinux image (autom4te: error: need GNU m4 1.4 or later). Fixed by build = ["missing", "m4/*"] in pyproject.toml under [tool.scikit-build-core-conan]. If this regresses, re-add the pattern.
  • [Unreleased] must stay present after stamping. Don't rename it to [X.Y.Z] - copy contents into a new [X.Y.Z] stanza and leave [Unreleased] empty. Otherwise the next release loses its scratchpad and the [Unreleased]: ref link points to a missing anchor.
  • Conan cache poisoning. Cache writers are split: build.yml's wheels job saves Release binaries built inside manylinux_2_31; ci.yml's coverage job saves Debug binaries built on the host. They live under different ${{ runner.os }}-conan-<type> keys so they don't collide. If a poisoned cache slips through (e.g. glibc symbol mismatch like _dl_find_object from a host-built cpptrace), purge with gh cache list --json id,key | jq ... | xargs gh cache delete.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.